From: Robert Klemme Date: 2008-09-22T14:21:53+09:00 Subject: Re: Grouping array elements while preserving order? On 21.09.2008 03:22, William James wrote: > On Sep 20, 4:47 pm, Matt Constantine 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