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 Sun, 2006-01-29 at 18:18 +0900, Johan Veenstra wrote:
On 1/28/06, Jonathan Leighton <lists@turnipspatch.com> 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/