From: Jonathan Leighton Date: 2006-01-29T21:03:33+09:00 Subject: Re: Loop weirdness On Sun, 2006-01-29 at 18:18 +0900, Johan Veenstra wrote: > The without the breaks if the last "cat[:num] == item[:num]" isn't true, " > add.call(item)" is executed, even if the item was already added to an > 'earlier' category Ah yes! Thanks, I didn't spot that. However, I still don't understand why the second break is necessary. Without it I get: [{:num=>1, :items=>["foo1"]}, {:num=>45, :items=>["foo45", "foo45"]}] [{:num=>1, :items=>["foo1", "foo1"]}, {:num=>45, :items=>["foo45", "foo45"]}] Which should be: [{:num=>1, :items=>["foo1"]}, {:num=>45, :items=>["foo45"]}] [{:num=>1, :items=>["foo1", "foo1"]}, {:num=>45, :items=>["foo45"]}] Any ideas on that? > by the way, your solution seems a bit complex, if you can live with a Hash > as the result, instead of an Array: > > def categorise( items ) > catHash = Hash.new { |h, k| Array.new } > items.each do | item | > catHash[ item[ :num ] ] += [ item[ :foo ] ] > end > catHash > 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' } ] ) > > {45 => [ "foo45" ], 1 => [ "foo1" ]} > {45 => [ "foo45" ], 1 => [ "foo1", "foo1" ]} > > if you can't live with that: > > def categorise( items ) > catHash = Hash.new { |h, k| Array.new } > items.each do | item | > catHash[ item[ :num ] ] += [ item[ :foo ] ] > end > catArray = [] > catHash.each do | num, foo | > catArray << { :num => num, :foo => foo } > end > catArray > end > > p categorize( [ { :num => 1, :foo => 'foo1' }, { :num => 45, :foo => 'foo45' > } ] ) > p categorize( [ { :num => 1, :foo => 'foo1' }, { :num => 45, :foo => 'foo45' > }, { :num => 1, :foo => 'foo1' } ] ) > > [{:num=>1, :items=>["foo1"]}, {:num=>45, :items=>["foo45"]}] > [{:num=>1, :items=>["foo1", "foo1"]}, {:num=>45, :items=>["foo45"]}] > > don't know about efficiency, but it look pretty simple These are interesting but unfortunately I need the order of the original items array to be maintained. This is because for the *actual* purpose, it's sorting a number of rows from a database and categorising them by a date field. The rows are returned in a certain order from the database and that order must be kept. Cheers > > On 1/28/06, Jonathan Leighton wrote: > > > > Hi, > > > > I'm going ever so slightly crazy over some looping behaviour. Here's a > > simplified test case I made: > > > > ---- > > def categorise(items) > > categorised = [] > > add = proc { |item| categorised << { :num => item[:num], :items => [ > > item[:foo] ] } } > > > > items.each do |item| > > if categorised.empty? > > add.call(item) > > else > > categorised.each do |cat| > > if cat[:num] == item[:num] > > cat[:items] << item[:foo] > > break > > elsif cat == categorised.last > > 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 > > http://turnipspatch.com/ | http://jonathanleighton.com/ | > > http://digital-proof.org/ > > > > > > -- Jonathan Leighton http://turnipspatch.com/ | http://jonathanleighton.com/ | http://digital-proof.org/