From: "s.ross" Date: 2009-07-20T04:43:26+09:00 Subject: Re: [Q] removing array duplicates where a subset is unique Hi--- On Jul 17, 2009, at 6:14 PM, David A. Black wrote: > Hi -- > > On Sat, 18 Jul 2009, brabuhr@gmail.com wrote: > >> On Fri, Jul 17, 2009 at 7:51 PM, Chuck >> Remes wrote: >>> (And Joel, I have presorted the array prior to removing the >>> dupes so I have already taken care of the ordering issue.) >> >> I think what Joel was referring to was that in Ruby 1.8 a Hash >> doesn't >> maintain insertion order when traversed (Ruby 1.9 does maintain >> insertion order): >> >> ruby 1.8.2 (2004-12-25) [powerpc-darwin8.0]: >> irb(main):001:0> h = {} >> => {} >> irb(main):002:0> 5.times{|n| h[n] = n} >> => 5 >> irb(main):003:0> h >> => {0=>0, 1=>1, 2=>2, 3=>3, 4=>4} >> irb(main):004:0> h["sadf"] = 3 >> => 3 >> irb(main):005:0> h >> => {0=>0, 1=>1, "sadf"=>3, 2=>2, 3=>3, 4=>4} > > If you wanted to maintain order you could (for some but probably not > much performance penalty) do something like: > > def dedup(ary) > uniq = {} > res = [] > ary.each do |line| > key = line[0..2] > next if uniq[key] > res << (uniq[key] = line) > end > res > end > > > David I missed the beginning of this thread, but here is an implementation I've used successfully: def uniq_by(subject, &block) h = {} a = [] subject.each do |s| comparator = yield(s) unless h[comparator] a.push(s) h[comparator] = s end end a end Usage: u = uniq_by(ary|{ |item| item.element } Basically, what this allows you to do is specify what exactly about an array item must be unique. It also preserves the original array order, with a "first entry wins" approach to duplicate elimination. Hope this is useful.