On 2006.01.29 07:05, Jonathan Leighton wrote:
> Hi,
>
> I'm going ever so slightly crazy over some looping behaviour. Here's a
> simplified test case I made:
I am feeling really dense today so I may be totally off mark, but...
> ----
> def categorise(items)
> categorised = []
> add = proc { |item| categorised << { :num => item[:num], :items => [ item[:foo] ] } }
>
> items.each do |item|
> if categorised.empty?
> add.call(item)
This is only done once, because categorised will no longer be empty.
> else
> categorised.each do |cat|
cat is the first and last element of categorised.
> if cat[:num] == item[:num]
> cat[:items] << item[:foo]
> break
> elsif cat == categorised.last
This will be true.
> add.call(item)
> break
> end
> end
> end
> end
>
> categorised
> end
>
> p categorise( [ { :num => 1, :foo => 'foo1' }, { :num => 45, :foo => 'foo45' } ] )
> p categorise( [ { :num => 1, :foo => 'foo1' }, { :num => 45, :foo => 'foo45' }, { :num => 1, :foo => 'foo1' } ] )
> ----
>
> Which produces:
>
> [{:num=>1, :items=>["foo1"]}, {:num=>45, :items=>["foo45"]}]
> [{:num=>1, :items=>["foo1", "foo1"]}, {:num=>45, :items=>["foo45"]}]
>
> Good-oh.
>
> HOWEVER, if I remove the breaks from the categorised loop, it produces
> all sorts of spectacular results (try it yourself). This I cannot
> understand:
>
> * For the first one, if cat[:num] == item[:num], this implies that
> there are no other instances of this particular number. Which of course
> is what I want. The break perhaps speeds things up because it doesn't
> have to iterate more than needed, but it shouldn't affect the end result
> as far as I can see.
> * For the second one, it should only be run if cat == categorised.last,
> ie we're on the last item in the array. Which means that the iteration
> should not be run again. So why does the break affect things?
>
> I'm really getting quite confused about this so I'd be really glad of an
> explanation.
>
> Thanks a lot
>
> Jonathan Leighton
E