Basically, I want to break from a find_all, and get the array of
elements found so far. Is this possible?
I tried this, no luck with find_all and collect, they return nil,
instead of the array so far. Any suggestions on how to do this?
This might be overly simplistic, but if this is not going to be used
by multiple threads simultaneously, and you already know the limit
ahead of time, why not just set the limit on the object before
calling the function, and make sure that each limits you to that?
class EveryN
include Enumerable
def initialize(n) @n = n
end
def each
y = 0
loop do
y = y + @n
break if @max_iteration < y
yield y
end
end
def max_iteration=(max_iteration) @max_iteration = max_iteration
end
end
every = EveryN.new(3)
every.max_iteration = 25
every.each { |n| puts n }
puts “is 20 in every?”
every.max_iteration = 20
p every.detect { |n| n == 20 }
puts “is 21 in every?”
every.max_iteration = 21
p every.detect { |n| n == 21 }
puts “all n between 100 and 200?”
every.max_iteration = 200
p every.find_all { |n| n >= 100}
puts “all n as a string, up to 20”
every.max_iteration = 20
p every.collect { |n| “n is #{n}” }
Walt
···
Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284
Why can you break from inject and get the result, but not from find_all
or collect?
Is this a bug, an oversight, or is something about the methods that
makes them need to be different?
I think the idea of breaking from find_all is sort of contradictory,
since it runs counter to the “all” part of “find_all”
But anyway… what Robert does is “break arr” – that is, he gives
break an argument. That argument then becomes the return value of the
whole thing. You can’t do that with find_all, because you don’t have
direct access to the accumulator (“arr” in Robert’s example).
Why can you break from inject and get the result, but not from find_all
or collect?
Is this a bug, an oversight, or is something about the methods that
makes them need to be different?
The difference is that in the inject version you have access to the array
that collects values and hence can transmit it to the caller via “break
arr”. The find_all version has no access to the array and thus you can’t
return the array via “break”.
I’m not sure whether “find_all” cannot be implemented differently because
I don’t know whether find_all can determine whether there was an argument
to “break” or not. Because if there was then that is clearly what you
want to be returned:
irb(main):006:0> (1…10).find_all {|x| break “early exit” if x % 2 == 0}
=> “early exit”
irb(main):007:0> (1…10).find_all {|x| break “early exit” if x % 26666 ==
0}
=>
Of course you can achieve the same without “inject” by using “return” in a
method:
def test(enum)
arr=
enum.each { |n| return arr if n > 200; arr<= 100 && n <= 200 }
arr
end
Although I have to admit that I find “inject” more beatiful…