I've never needed to do this in Ruby, but my boss, being a C programmer, has put to me a problem that I honestly can't provide an elegant solution for in Ruby, without basically doing it in the C way (tracking a variable an using two "break" statements).
We have a situation like this (parsing XML):
(1..1000).each do |page|
fetch_page(page).results.each do |re开发者_高级运维sults|
do_something_with_results!
break if results[:some_value] > another_value # this needs to exit BOTH blocks
end
end
The only way I could do this is in a way that I would not describe as being very Ruby-like, and more a C way of thinking. Something like:
(1..1000).each do |page|
should_break = false
fetch_page(page).results.each do |results|
do_something_with_results!
if results[:some_value] > another_value
should_break = true
break
end
end
break if should_break
end
That to me feels completely wrong and un-Ruby-like, but what's the functional approach?
catch (:break) do
(1..1000).each do |page|
fetch_page(page).results.each do |results|
do_something_with_results!
throw :break if results[:some_value] > another_value # this needs to exit BOTH blocks
end
end
end
EDIT: @CaptainPete's comment above is spot on. If you can make it into a function, it has significant side benefits (unit testing being the primary one).
It depends on your circumstances.
If the data sets aren't too large, you could do
results = (1..1000).map{|page_number| fetch_page(page_number).results}.flatten(1)
results.each do
do_something_with_results!
break if results[:some_value] > another_value # this needs to exit BOTH blocks
end
otherwise you'd have to do something to make it more lazy, such as
def each_result(page_numbers)
page_numbers.each do |page_number|
fetch_page(page_number).results.each do |result|
yield result
end
end
end
and I'm sure there are many other ways for making something lazy.
精彩评论