From: Raf Coremans Date: 2007-05-04T04:38:59+09:00 Subject: Re: array slicing 2007/5/3, Josselin : > On 2007-05-03 17:38:57 +0200, "Raf Coremans" said: > > > 2007/5/3, Josselin : > >> given an array > >> > >> anArray = [["a", 1, 1], ["b", 1, 2], ["c", 1, 5], ["z", 1, 1], ["e", 1, > >> 5], ["f", 1, 6], ["g", 1, 1], ["h", 1, 3], ["i", 1, 1], ["j", 1, 2], > >> ["k", 1, 1], ["y", 1, 6], ["m", 1, 1], ["u", 1, 2], ["v", 1, 1], ["p", > >> 1, 4], ["q", 1, 5], ["r", 1, 1], ["n", 1, 1], ["t", 2, 3], ["s", 2, 2], > >> ["o", 2, 1], ["w", 2, 1], ["x", 2, 1], ["l", 2, 1], ["d", 2, 1]] > >> > >> I would like to get it sliced in groups of element having the same 2nd > >> and 3rd values > >> > >> sliced_array = [ > >> [ ["a", 1, 1],["g", 1, 1], ["i", 1, 1], ["k", 1, 1], ["m", 1, 1], ["n", > >> 1, 1],["r", 1, 1],["v", 1, 1],["z", 1, 1] ], > >> [ ["b", 1, 2],["j", 1, 2], ["u", 1, 2] ], > >> [ ["c", 1, 5],["e", 1, 5],["q", 1, 5] ], > >> [ ["d", 2, 1],["l", 2, 1], ["l", 2, 1], ["o", 2, 1],["w", 2, 1],["x", 2, 1] ], > >> [ ["f", 1, 6],["y", 1, 6] ], > >> [ ["h", 1, 3] ], > >> [ ["p", 1, 4] ], > >> [ ["s", 2, 2] ], > >> [ ["t", 2, 3] ] > >> ] > > > > Applying a trick I learned today: > > > > anArray.inject( Hash.new{ |hash, key| hash[key] =[] } ){ |hash, > > subarray| hash[subarray[1, 2]] << subarray; hash }.values > > > > Or if you need a sorted result: > > > > anArray.inject( Hash.new{ |hash, key| hash[key] =[] } ){ |hash, > > subarray| hash[subarray[1, 2]] << subarray; hash }.values.sort_by{ > > |subarray| subarray[0][1,2] } > > > > > > Best regards, > > Raf > > good to know , what about the partition_by , it seems simple ? > > module Enumerable > def partition_by > r = Hash.new{ |h,k| h[k]=[] } > each do |e| > r[ yield(e) ] << e > end > return r > end > end > > And then : > > require 'enumerator' > sArray = anArray.sort_by {|item| [item[1], item[2] ] } > > sArray.partition_by {|ary| ary[1..2]}.to_enum(:each_value).to_a=> > [[["j", 1, 2], ["u", 1, 2], ["b", 1, 2]], [["l", 2, 1], ["x", 2, 1], > ["o", 2, 1], ["w", 2, 1], ["d", 2, 1]], [["a", 1, 1], ["z", 1, 1], > ["v", 1, 1], ["r", 1, 1], ["i", 1, 1], ["m", 1, 1], ["g", 1, 1], ["k", > 1, 1], ["n", 1, 1]], [["f", 1, 6], ["y", 1, 6]], [["t", 2, 3]], [["c", > 1, 5], ["e", 1, 5], ["q", 1, 5]], [["s", 2, 2]], [["p", 1, 4]], [["h", > 1, 3]]] > > and that's it..... > > > Yes. I think it could be improved though: module Enumerable def partition_by inject( Hash.new{ |h,k| h[k]=[] } ){ |h, e| h[ yield( e)] << e; h }.values end end p anArray.partition_by { |e| e[1, 2] } => [[["b", 1, 2], ["j", 1, 2], ["u", 1, 2]], [["o", 2, 1], ["w", 2, 1], ["x", 2, 1], ["l", 2, 1], ["d", 2, 1]], [["a", 1, 1], ["z", 1, 1], ["g", 1, 1], ["i", 1, 1], ["k", 1, 1], ["m", 1, 1], ["v", 1, 1], ["r", 1, 1], ["n", 1, 1]], [["f", 1, 6], ["y", 1, 6]], [["t", 2, 3]], [["c", 1, 5], ["e", 1, 5], ["q", 1, 5]], [["s", 2, 2]], [["p", 1, 4]], [["h", 1, 3]]] Or if you want it sorted: p anArray.sort.partition_by{ |subarray| subarray[1, 2] }.sort_by{ |e| e[0][1,2] } => [[["a", 1, 1], ["g", 1, 1], ["i", 1, 1], ["k", 1, 1], ["m", 1, 1], ["n", 1, 1], ["r", 1, 1], ["v", 1, 1], ["z", 1, 1]], [["b", 1, 2], ["j", 1, 2], ["u", 1, 2]], [["h", 1, 3]], [["p", 1, 4]], [["c", 1, 5], ["e", 1, 5], ["q", 1, 5]], [["f", 1, 6], ["y", 1, 6]], [["d", 2, 1], ["l", 2, 1], ["o", 2, 1], ["w", 2, 1], ["x", 2, 1]], [["s", 2, 2]], [["t", 2, 3]]] Regards, Raf