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