防止重复项添加到 Ruby 对象数组中

3
如何使用对象属性匹配相同对象,从Ruby对象数组中消除重复元素?
对于基本类型的数组,可以使用集合来实现。
例如:
array_list = [1, 3, 4 5, 6, 6]
array_list.to_set 
=> [1, 2, 3, 4, 5, 6]

我能否将这种技术应用于对象属性?

谢谢。


1
请参考以下链接:https://dev59.com/gnVD5IYBdhLWcg3wDG_l#113770 - steenslag
5个回答

3
我认为你把本末倒置了。你问自己:“如何让uniq删除不相等的对象?”但是,你应该问自己的是:“尽管我认为它们是相等的,但这两个对象为什么不相等呢?”
换句话说:看起来你正在试图解决对象具有破损的相等语义的问题,而你真正应该做的是简单地修复这些破损的相等语义。
以下是一个Product的示例,如果两个产品具有相同的类型编号,则认为它们相等:
class Product
  def initialize(type_number)
    self.type_number = type_number
  end

  def ==(other)
    type_number == other.type_number
  end

  def eql?(other)
    other.is_a?(self.class) && type_number.eql?(other.type_number)
  end

  def hash
    type_number.hash
  end

  protected

  attr_reader :type_number

  private

  attr_writer :type_number
end

require 'test/unit'
class TestHashEquality < Test::Unit::TestCase
  def test_that_products_with_equal_type_numbers_are_considered_equal
    assert_equal 2, [Product.new(1), Product.new(2), Product.new(1)].uniq.size
  end
end

Jörg,如果我想使用type_number来考虑我的产品在一个用途中的唯一性,但在另一个用途中使用不同的字段,比如color,该怎么办呢?理想情况下,能够像常见的用于排序的比较方法一样,使用一个块来实现这个功能会很好。有什么想法吗? - maček
你好。理想情况下,我希望在对象数组中阻止对象的重复添加(基于相匹配的属性)。我认为集合可能可以做到这一点。 - Dom

2

如果您可以将eql?写入您的对象中,则可以使用uniq


1

关于uniq怎么样?

   a = [ "a", "a", "b", "b", "c" ]
   a.uniq   #=> ["a", "b", "c"]

你也可以在对象上使用它!


他说了对象属性,所以我猜完整的对象不会完全相同。 - Beanish
嗨.. Beanish 是对的.. 需要匹配实例的对象 ID... 我可以将一个 block 传递给 to_set 或 uniq 方法吗? - Dom
@Dom:看起来你可以将一个块传递给 to_set 方法:http://apidock.com/ruby/Enumerable/to_set。虽然没有明确说明它的具体作用,但我猜想它可能会解决你的问题。 - ryeguy
@ryeguy,*args&block只是被发送到Set#initialize函数中。 - maček

0

你应该使用Array还是应该使用Set?如果顺序不重要,那么后者将更高效地检查重复项。


-1
感谢您的回复。在我的对象模型中添加以下内容后,uniq功能正常运行。
def ==(other)
    other.class == self.class &&
    other.id  == self.id
end
alias :eql? :==

1
这违反了Object#hash的约定,可能也违反了Object#==的约定。 - Jörg W Mittag

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接