Comparing elements within an array

I’m familiar with the enumberable sort method …
my_array.sort { |a,b| a.property <=> b.property }

and I’m familiar with reject and delete_if methods …
my_array.delete_if { |a| }

but can someone advise me on a simple way to compare elements within an
array and delete one if a certain property is the same as another
element e.g.

my_array.special_delete_if { |a,b| a.property == b.property }

Note, the reason I can’t just use my_array.uniq is that the array is
made up of objects which are themselves unique, it is just that some
elements share the same property (and these are the ones I want to
collapse down to just one object).

Thanks in advance!

On Fri, May 14, 2010 at 12:47 PM, Toby R. [email protected] 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 :frowning:
HTH
R.

Robert D. 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 :frowning: Any ideas?

On Fri, May 14, 2010 at 12:47 PM, Toby R. [email protected] 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 :frowning:
HTH
R.

On Fri, May 14, 2010 at 4:19 PM, alexg [email protected] wrote:

On Fri, 14 May 2010 22:03:21 +0900, Toby R. [email protected] wrote:
yes I do not worry about 1.8 much anymore, not very considerate of me
though, sorry
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
which is better than tap anyway :slight_smile:

R.

On Fri, 14 May 2010 22:03:21 +0900, Toby R. [email protected]
wrote:

Robert D. 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 :frowning: Any ideas?

On Fri, May 14, 2010 at 12:47 PM, Toby R. [email protected]
wrote:
}
end
end

p [*1…10].unique_by{ |x| x % 3 }

Could’nt come up with something more concise :frowning:
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 G.

Yup, that all works - thanks to you both!

kind regards
Toby