Skip to main content

Getting Ruby Array.uniq! work for array of objects

Иногда возникает задача удалить дубликаты из массива объектов. В Ruby для решения этой задачи в классе Array есть методы uniq и uniq!. Отличие первого от второго состоит лишь в том, что второй производит in place модификацию массива, а первый возвращает результат в виде массива. Для того, чтобы эти методы работали для custom классов необходимо чтобы у классов были определены методы hash и eql?.

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+.

Comments

  1. Вот такие вот нестыковки меня периодически просто убивают. Хотя в целом, язык великолепный.

    ReplyDelete
  2. да ну в принципе терпимо, если интернет под рукой есть =)

    ReplyDelete
  3. Ну, терпеть можно многое. Я надеюсь, что в Rubinius (на который я возлагаю много надежд) многие из таких вот вещей вылечат. Ну и, конечно, Matz суров. Делать Array#uniq через Hash...

    ReplyDelete
  4. Делать Array#uniq через Hash
    Я думаю он тут руководствовался вопросами эффективности

    ReplyDelete

Post a Comment

СООБЩЕНИЕ СПАМЕРАМ: прежде чем пытаться оставить ссылку на свой ресурс в комментарии, прошу обратить внимание на тег nofollow, которым они помечены и зря не терять ни свое ни мое время. А будете упорствовать еще и noindex поставлю