From: alexg Date: 2010-05-14T23:19:11+09:00 Subject: Re: Comparing elements within an array On Fri, 14 May 2010 22:03:21 +0900, Toby Rodwell wrote: > Robert Dober wrote: > Many thanks for this, and you ahve exactly described what I am wanting > to do. Unfortunately it is throwing up 'undefined method `tap' for > nil:NilClass (NoMethodError)'. I tried figuring this out for myself but > no joy :( Any ideas? > >> On Fri, May 14, 2010 at 12:47 PM, Toby Rodwell wrote: >> >> ah a #unique_by, I therefore conclude that you want to keep one >> element with the given property. >> >> module Enumerable >> def unique_by &blk >> keys = {} >> reject{ | ele | >> key = blk[ele] >> keys[key].tap{ keys[key]=true } >> } >> end >> end >> >> p [*1..10].unique_by{ |x| x % 3 } >> >> Could'nt come up with something more concise :( >> HTH >> R. The code is ruby 1.9 only I think. Another way for 1.8.6: module Enumerable def unique_by &blk keys = {} find_all{ | ele | key = blk[ele] keys.has_key?(key) ? false : keys[key] = true } end end p [1,2,3,4,5].unique_by{ |x| x % 3 } Or you can temporarily redefine eql? and hash: class Foo attr_reader :a def initialize(a) @a = a end end bar = Foo.new(1) baz = Foo.new(2) boz = Foo.new(2) puts [bar,baz,boz].uniq.size class Foo alias_method :old_eql?, :eql? alias_method :old_hash, :hash def eql?(baz) @a == baz.a end def hash @a.hash end end puts [bar,baz,boz].uniq.size class Foo alias_method :eql?, :old_eql? alias_method :hash, :old_hash end puts [bar,baz,boz].uniq.size Alex Gutteridge