2010/8/27 timr <timrandg / gmail.com>:
> I am wondering if anyone has implemented an Array#collect_until method
> to break out of a collect loop after an end-point has been achieved
> during an Array#collect call.
>
> For instance, you have a long array of items and want to use each item
> to calculate something, but should the calculation give a specific
> result, then you know you are done--no need for processing the rest of
> the array. However, if that specified result is not met, the
> processing continues. Something like below:
>
> [1,2,3].collect{|item| item + 10} # => [11,12,13]
> [1,2,3].collect_until({|x| x%2 == 0}) {|item| item + 10} # => [11,12]

This would not work - it does not even parse

irb(main):004:0> 09:04:52 ~$ ruby19 -ce '[1,2,3].collect_until({|x|
x%2 == 0}) {|item| item + 10}'
-e:1: syntax error, unexpected '|', expecting '}'
[1,2,3].collect_until({|x| x%2 == 0}) {|item| item + 10}
                        ^
-e:1: syntax error, unexpected '}', expecting $end
[1,2,3].collect_until({|x| x%2 == 0}) {|item| item + 10}
                                    ^
09:04:59 ~$

You could at least have to use 'lambda' or 'proc':

09:04:59 ~$ ruby19 -ce '[1,2,3].collect_until(lambda {|x| x%2 == 0})
{|item| item + 10}'
Syntax OK


> To get this to work the result from the yield to {|item| item + 10}
> block would be run through the {|x| x%2 == 0} block to check if we are
> done.

You can use #inject for this:

irb(main):002:0> [1,2,3].inject([]){|a,x| a << (x+10); break a if x % 2 == 0;a}
=> [11, 12]

It also works if the condition never fires:

irb(main):003:0> [1,3,5].inject([]){|a,x| a << (x+10); break a if x % 2 == 0;a}
=> [11, 13, 15]

Kind regards

robert

-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/