Иногда возникает задача удалить дубликаты из массива объектов. В Ruby для решения этой задачи в классе Array есть методы uniq и uniq!. Отличие первого от второго состоит лишь в том, что второй производит in place модификацию массива, а первый возвращает результат в виде массива. Для того, чтобы эти методы работали для custom классов необходимо чтобы у классов были определены методы hash и eql?.
Update 20:10: тут меня коллеги попинали чуток, так что слегка изменил пример ;-). И почему мне сразу в голову не пришла мысль, что String.hash есть?
Update 25/11/2008: в ri Hash собственно нашлось объяснение :) : +Hash+ uses +key.eql?+ to test keys for equality. If you need to use instances of your own classes as keys in a +Hash+, it is recommended that you define both the +eql?+ and +hash+ methods. The +hash+ method must have the property that +a.eql?(b)+ implies +a.hash == b.hash+.
class TestClass
attr_reader :a, :b, :c
#Ctor
def initialize(a,b,c)
@a, @b, @c = a, b, c
end
def hash
"#@a #@b #@c".hash
end
def ==(p)
@a ==p.a and @b == p.b and @c == p.c
end
def eql?(p)
self == p
end
def to_s
"#@a,#@b,#@c"
end
end
a = []
a << TestClass.new(1,2,3)
a << TestClass.new(1,2,3)
a << TestClass.new(3,2,1)
a << TestClass.new(3,2,3)
a << TestClass.new(2,3,3)
a.uniq!
a.each do |elem|
p elem.to_s
end
Т.е. одного eql? не достаточно, как это указано в PickAxe а нужен еще и hash method который должен возвращать целое число. И чтобы я делал, если бы не USENET?Update 20:10: тут меня коллеги попинали чуток, так что слегка изменил пример ;-). И почему мне сразу в голову не пришла мысль, что String.hash есть?
Update 25/11/2008: в ri Hash собственно нашлось объяснение :) : +Hash+ uses +key.eql?+ to test keys for equality. If you need to use instances of your own classes as keys in a +Hash+, it is recommended that you define both the +eql?+ and +hash+ methods. The +hash+ method must have the property that +a.eql?(b)+ implies +a.hash == b.hash+.
Вот такие вот нестыковки меня периодически просто убивают. Хотя в целом, язык великолепный.
ReplyDeleteда ну в принципе терпимо, если интернет под рукой есть =)
ReplyDeleteНу, терпеть можно многое. Я надеюсь, что в Rubinius (на который я возлагаю много надежд) многие из таких вот вещей вылечат. Ну и, конечно, Matz суров. Делать Array#uniq через Hash...
ReplyDeleteДелать Array#uniq через Hash
ReplyDeleteЯ думаю он тут руководствовался вопросами эффективности