了解Array#uniq函数调用

时间:2015-01-31 22:07:23

标签: ruby

如果我使用以下代码:

class Item
  attr_reader :item_name, :qty

  def initialize(item_name, qty)
    @item_name = item_name
    @qty = qty
  end

  def to_s
   "Item (#{@item_name}, #{@qty})"
  end

  def hash
    p "hash has been called"
    self.item_name.hash ^ self.qty.hash
  end

  def eql?(other_item)
    puts "#eql? invoked"
    @item_name == other_item.item_name && @qty == other_item.qty
  end  
end

p Item.new("abcd", 1).hash

items = [Item.new("abcd", 1), Item.new("abcd", 1), Item.new("abcd", 1)]
p items.uniq

"hash has been called"
4379041107527942435
"hash has been called"
"hash has been called"
#eql? invoked
"hash has been called"
#eql? invoked
"hash has been called"
"hash has been called"
"hash has been called"
[Item (abcd, 1)]

我正在解释这意味着#hash方法被用于为每个对象生成唯一的整数,然后#eql?调用以检查整数是否相等,以检查重复项。我的解释是否正确?

1 个答案:

答案 0 :(得分:4)

不,你的解释不正确。

hash 生成唯一的整数,这正是为什么 eql?调用是必要的,eql?是< em> not 在整数上调用,但在元素上调用。

这只是普通的旧哈希,与HashSetSortedSet中使用的完全相同。

hash是一个哈希函数,即将一个大的(可能是无限的)输入空间映射到一个较小的固定大小的输出空间的函数。由于输出空间小于输入空间,必须必须至少有两个具有相同哈希码的不同对象,因此哈希值唯一! (这被称为 Pigeonhole Principle 。直观地说:如果你有两个抽屉和三个袜子,那么必须至少有一个抽屉里面至少有两个袜子。)

因为哈希值不是唯一的,所以两个相同的哈希值不会告诉您任何内容。如果两个哈希值不同,那么您知道肯定这两个对象也是不同的。但是如果两个哈希值是相同,那么对象可能仍然不同(这称为 Hash Collision ),这就是为什么你有使用eql?进行仔细检查。