From: Robert Klemme Date: 2006-12-07T18:05:05+09:00 Subject: Re: [GOLF]: partitioning an array On 07.12.2006 09:46, Ross Bamford wrote: > On Thu, 07 Dec 2006 03:46:37 -0000, Max Muermann 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)]||=[])<> 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]||=[])< # => [["a", "g", "m"], ["bc", "hi"], ["def", "jkl"]] But: >> %w{a bbb}.inject([]){|dst,e|(dst[e.length-1]||=[])< [["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