From: Johan Veenstra Date: 2006-01-29T18:18:46+09:00 Subject: Re: Loop weirdness ------=_Part_7021_26703939.1138526312172 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline The without the breaks if the last "cat[:num] =3D=3D item[:num]" isn't true= , " add.call(item)" is executed, even if the item was already added to an 'earlier' category 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 =3D Hash.new { |h, k| Array.new } items.each do | item | catHash[ item[ :num ] ] +=3D [ item[ :foo ] ] end catHash end p categorise( [ { :num =3D> 1, :foo =3D> 'foo1' }, { :num =3D> 45, :foo =3D= > 'foo45' } ] ) p categorise( [ { :num =3D> 1, :foo =3D> 'foo1' }, { :num =3D> 45, :foo =3D= > 'foo45' }, { :num =3D> 1, :foo =3D> 'foo1' } ] ) {45 =3D> [ "foo45" ], 1 =3D> [ "foo1" ]} {45 =3D> [ "foo45" ], 1 =3D> [ "foo1", "foo1" ]} if you can't live with that: def categorise( items ) catHash =3D Hash.new { |h, k| Array.new } items.each do | item | catHash[ item[ :num ] ] +=3D [ item[ :foo ] ] end catArray =3D [] catHash.each do | num, foo | catArray << { :num =3D> num, :foo =3D> foo } end catArray end p categorize( [ { :num =3D> 1, :foo =3D> 'foo1' }, { :num =3D> 45, :foo =3D= > 'foo45' } ] ) p categorize( [ { :num =3D> 1, :foo =3D> 'foo1' }, { :num =3D> 45, :foo =3D= > 'foo45' }, { :num =3D> 1, :foo =3D> 'foo1' } ] ) [{:num=3D>1, :items=3D>["foo1"]}, {:num=3D>45, :items=3D>["foo45"]}] [{:num=3D>1, :items=3D>["foo1", "foo1"]}, {:num=3D>45, :items=3D>["foo45"]}= ] don't know about efficiency, but it look pretty simple 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 =3D [] > add =3D proc { |item| categorised << { :num =3D> item[:num], :items =3D= > [ > item[:foo] ] } } > > items.each do |item| > if categorised.empty? > add.call(item) > else > categorised.each do |cat| > if cat[:num] =3D=3D item[:num] > cat[:items] << item[:foo] > break > elsif cat =3D=3D categorised.last > add.call(item) > break > end > end > end > end > > categorised > end > > p categorise( [ { :num =3D> 1, :foo =3D> 'foo1' }, { :num =3D> 45, :foo = =3D> > 'foo45' } ] ) > p categorise( [ { :num =3D> 1, :foo =3D> 'foo1' }, { :num =3D> 45, :foo = =3D> > 'foo45' }, { :num =3D> 1, :foo =3D> 'foo1' } ] ) > ---- > > Which produces: > > [{:num=3D>1, :items=3D>["foo1"]}, {:num=3D>45, :items=3D>["foo45"]}] > [{:num=3D>1, :items=3D>["foo1", "foo1"]}, {:num=3D>45, :items=3D>["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] =3D=3D 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 =3D=3D categorised.las= t, > 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/ > > > ------=_Part_7021_26703939.1138526312172--