Robert Klemme
9/22/2008 5:27:00 AM
On 21.09.2008 03:22, William James wrote:
> On Sep 20, 4:47 pm, Matt Constantine <desig...@gmail.com> wrote:
>> Hi all,
>>
>> I've run into a number of situations where I need to group an array
>> while preserving order. For example, grouping the results of a database
>> query without affecting their order or introducing extraneous logic in a
>> view.
>>
>> I would like to know if there are any obvious problems or improvements
>> to this solution:
>>
>> class Array
>> def partition_by(&b)
>> out=[]
>> self.inject([]) {|acc,e|
>> last = acc.pop
>> value = b.call(e)
>> out << {value=>[]} if last != value
>> out.last[value] << e
>> acc << value
>> }
>> out
>> end
>> end
>>
>> So if I partition an array by element length, for example (contrived, I
>> know):
>> animals = %w(dog dog cat chicken chicken dog)
>> animals.partition_by{|x| x.length}
>>
>> I get:
>> [{3=>["dog", "dog", "cat"]}, {7=>["chicken", "chicken"]}, {3=>["dog"]}]
>
> Without hashes:
>
> class Array
> def group_by
> key = nil
> inject([]){|result,x|
> k = yield x
> if key == k and result != []
> result[-1] << x
> next result
> end
> key = k
> result << [x]
> }
> end
> end
You're loosing keys there. Maybe rather
module Enumerable
def group_by_ordered
inject([]) do |agg, v|
k = yield v
if agg.empty? || k != agg.last.first
agg << [k, [v]]
else
agg.last.last << v
end
agg
end
end
end
irb(main):014:0> animals = %w(dog dog cat chicken chicken dog)
=> ["dog", "dog", "cat", "chicken", "chicken", "dog"]
irb(main):015:0> animals.group_by_ordered {|x| x.length}
=> [[3, ["dog", "dog", "cat"]], [7, ["chicken", "chicken"]], [3, ["dog"]]]
irb(main):016:0>
Cheers
robert