Robert Klemme
12/7/2006 9:01:00 AM
On 07.12.2006 09:46, Ross Bamford wrote:
> On Thu, 07 Dec 2006 03:46:37 -0000, Max Muermann <ruby@muermann.org> wrote:
>
>> Take an array of objects and partition it into subarrays, based on
>> some arbitrary property of the objects. I would use this for example
>> for generating a report of purchase orders and grouped by week, month,
>> year, approximate value, etc.
>>
>> The idea is similar to Array#partition, but where partition only does
>> a true/false check, the resulting array should be partitioned by the
>> return value of a block so that:
>>
>> a = ['a','bc','def','g','hi','jkl','m']
>> group(a) {|i| i.size} #=> [["a", "g", "m"], ["bc", "hi"], ["def", "jkl"]]
>>
>>
>> My best effort so far is this:
>>
>> def group array, &block
>> h = {}
>> array.each do |e|
>> (h[yield(e)]||=[])<<e
>> end
>> h.to_a.map {|e| e[1] }
The last line is definitively superfluous in the light of Hash#values.
>> end
>>
>> For some reason, I cannot bring myself to like this. I have the
>> nagging feeling that there is a more elegant way...
>
> Maybe:
>
> a = ['a','bc','def','g','hi','jkl','m']
> # => ["a", "bc", "def", "g", "hi", "jkl", "m"]
>
> a.inject([]){|dst,e|(dst[e.length-1]||=[])<<e;dst}
> # => [["a", "g", "m"], ["bc", "hi"], ["def", "jkl"]]
But:
>> %w{a bbb}.inject([]){|dst,e|(dst[e.length-1]||=[])<<e;dst}
=> [["a"], nil, ["bbb"]]
I did
>> a = ['a','bc','def','g','hi','jkl','m']
=> ["a", "bc", "def", "g", "hi", "jkl", "m"]
>> a.inject(Hash.new {|h,k| h[k]=[]}) {|r,x| r[x.size] << x; r}.values
=> [["a", "g", "m"], ["bc", "hi"], ["def", "jkl"]]
>> %w{a bbb}.inject(Hash.new {|h,k| h[k]=[]}) {|r,x| r[x.size] << x;
r}.values
=> [["a"], ["bbb"]]
Whether that's nicer - I don't know.
Kind regards
robert