python对象集合中的标识。和散列

python对象集合中的标识。和散列,python,object,hash,set,identity,Python,Object,Hash,Set,Identity,散列和等式在集合标识中如何使用? 例如,一些有助于解决某些domino难题的代码: class foo(object): def __init__(self, one, two): self.one = one self.two = two def __eq__(self,other): if (self.one == other.one) and (self.two == other.two): return True

散列和等式在集合标识中如何使用? 例如,一些有助于解决某些domino难题的代码:

class foo(object):
    def __init__(self, one, two):
        self.one = one
        self.two = two
    def __eq__(self,other):
        if (self.one == other.one) and (self.two == other.two): return True
        if (self.two == other.one) and (self.one == other.two): return True
        return False
    def __hash__(self):
        return hash(self.one + self.two)

s = set()

for i in range(7):
    for j in range(7):
        s.add(foo(i,j))
len(s) // returns 28 Why?
如果我只使用uuu eq uuu()len(s)等于49。这没关系,因为据我所知,对象(例如1-2和2-1)并不相同,但表示相同的domino。因此,我添加了哈希函数。

现在它以我想要的方式工作,但我不明白一件事:1-3和2-2的散列应该是相同的,所以它们应该像相同的对象一样计数,不应该添加到集合中。但他们确实如此!我被卡住了。

您可以在Python中了解这一点,但简单的回答是您可以将哈希函数重写为:

def __hash__(self):
    return hash(tuple(sorted((self.one, self.two))))

您可以在Python中了解这一点,但简短的回答是您可以将哈希函数重写为:

def __hash__(self):
    return hash(tuple(sorted((self.one, self.two))))

散列只是帮助Python排列对象的提示。在一个集合中查找某个对象时,它仍然必须使用与
foo
相同的哈希值检查集合中的每个对象

这就像有一个书架放着字母表中的每个字母。假设你想在你的收藏中增加一本新书,但前提是你还没有这本书的副本;你应该先到书架上找合适的信。但是,你必须看书架上的每一本书,并将其与你手中的一本进行比较,看看是否相同。你不会因为书架上已经有东西就扔掉这本新书


如果您想使用一些其他值来过滤掉“重复项”,那么使用一个dict将domino的总值映射到您看到的第一个domino。不要颠覆内置Python行为,使其具有完全不同的含义。(正如您所发现的,无论如何,在这种情况下它不起作用。)

哈希只是帮助Python排列对象的提示。在一个集合中查找某个对象时,它仍然必须使用与
foo
相同的哈希值检查集合中的每个对象

这就像有一个书架放着字母表中的每个字母。假设你想在你的收藏中增加一本新书,但前提是你还没有这本书的副本;你应该先到书架上找合适的信。但是,你必须看书架上的每一本书,并将其与你手中的一本进行比较,看看是否相同。你不会因为书架上已经有东西就扔掉这本新书


如果您想使用一些其他值来过滤掉“重复项”,那么使用一个dict将domino的总值映射到您看到的第一个domino。不要颠覆内置Python行为,使其具有完全不同的含义。(正如您所发现的,在这种情况下,它无论如何都不起作用。)

dict/set目的的相等取决于
\uuuu eq\uuu
定义的相等。但是,要求比较相等的对象具有相同的哈希值,这就是为什么需要
\uuuuuhash\uuuu
。有关类似的讨论,请参见

哈希本身并不确定两个对象在字典中的计数是否相同。散列就像一个“快捷方式”,只有一种方式有效:如果两个对象有不同的散列,它们肯定不相等;但是如果它们有相同的散列,它们仍然可能不相等

在您的示例中,您定义了
\uuuuuuuhash\uuuuu
\uuuuuueq\uuuuu
来执行不同的操作。散列仅取决于domino上的数字之和,但相等性取决于两个单独的数字(顺序)。这是合法的,因为同样的多米诺骨牌也有同样的散列。然而,正如我上面所说的,这并不意味着等额多米诺骨牌会被认为是相等的。一些不相等的多米诺骨牌仍然有相等的散列。但是相等性仍然是由
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
决定的,而且
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuueq
仍然按顺序查看这两个数字,因此这就是决定它们是否相等的原因


在我看来,在你的情况下,合适的做法是定义
\uuuuuuhash\uuuuuuuu
\uuuuuuuuueq\uuuuuuu
依赖于有序对,也就是说,首先比较两个数字中的较大者,然后比较较小者。这将意味着2-1和1-2将被视为相同。

出于dict/set目的的相等性取决于
\uuuuuu eq\uuuu
定义的相等性。但是,要求比较相等的对象具有相同的哈希值,这就是为什么需要
\uuuuuhash\uuuu
。有关类似的讨论,请参见

哈希本身并不确定两个对象在字典中的计数是否相同。散列就像一个“快捷方式”,只有一种方式有效:如果两个对象有不同的散列,它们肯定不相等;但是如果它们有相同的散列,它们仍然可能不相等

在您的示例中,您定义了
\uuuuuuuhash\uuuuu
\uuuuuueq\uuuuu
来执行不同的操作。散列仅取决于domino上的数字之和,但相等性取决于两个单独的数字(顺序)。这是合法的,因为同样的多米诺骨牌也有同样的散列。然而,正如我上面所说的,这并不意味着等额多米诺骨牌会被认为是相等的。一些不相等的多米诺骨牌仍然有相等的散列。但是相等性仍然是由
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
决定的,而且
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuueq
仍然按顺序查看这两个数字,因此这就是决定它们是否相等的原因


在我看来,在你的情况下,合适的做法是定义
\uuuuuuhash\uuuuuuuu
\uuuuuuuuueq\uuuuuuu
依赖于有序对,也就是说,首先比较两个数字中的较大者,然后比较较小者。这意味着2-1和1-2将被视为相同。

哈希函数的要求是,如果两个值的
x==y
,则
hash(x)==hash(y)
。反之亦然

通过考虑字符串的散列,可以很容易地看出为什么会出现这种情况。假设
hash(str)
返回一个32位的数字,我们对长度超过4个字符(即包含超过32个bi)的字符串进行哈希运算
{3: '1'}
pair = '12'
pair_key = sum(map(int, pair))
domino_pairs[pair_key] = int(pair[0]) # Store the first pair's first value.
# Retrieve pair from dictionary.
print pair_key - domino_pairs[pair_key] # 3-1 = 2
2
def add_pair(dct, pair):
  pair_key = sum(map(int, pair))
  if pair_key not in dct:
    dct[pair_key] = []
  dct[pair_key].append(int(pair[0]))

domino_pairs = {}
add_pair(domino_pairs, '22')
add_pair(domino_pairs, '04')
print domino_pairs
{4: [2, 0]}
domino_pairs = {}
add_pair(domino_pairs, '40')
add_pair(domino_pairs, '04')
print domino_pairs
   {4: [4, 0]}
 def has_pair(dct, pair):
  pair_key = sum(map(int, pair))
  if pair_key not in dct:
    return False
  return (int(pair[0]) in dct[pair_key] or 
    int(pair[1]) in dct[pair_key])
def add_pair(dct, pair):
  pair_key = sum(map(int, pair))
  if has_pair(dct, pair):
    return
  if pair_key not in dct:
    dct[pair_key] = []
  dct[pair_key].append(int(pair[0])) 
domino_pairs = {}
add_pair(domino_pairs, '40')
add_pair(domino_pairs, '04')
print domino_pairs
{4: [4]}
def print_pairs(dct):
  for total in dct:
    for a in dct[total]:
      a = int(a)
      b = int(total) - int(a)
      print '(%d, %d)'%(a,b)
domino_pairs = {}
add_pair(domino_pairs, '40')
add_pair(domino_pairs, '04')
add_pair(domino_pairs, '23')
add_pair(domino_pairs, '50')
print_pairs(domino_pairs)
(4, 0)
(2, 3)
(5, 0)