不可哈希对象的无序集合?

8 投票
2 回答
753 浏览
提问于 2025-04-17 07:25

我有一个字典,其中一些值是不可哈希的。这意味着我不能直接用它们来比较两个无序的组,以确保它们包含相同的元素。我不能用列表,因为列表的比较会考虑顺序,但集合也不行,因为字典本身是不可哈希的。我查了一下Python的文档,发现唯一看起来有用的就是字典的视图,在某些情况下它是可哈希的,但在这种情况下也没用,因为其中一个值是一个包含列表的对象,这样字典的视图也就不可哈希了。

有没有什么标准的容器可以处理这种情况,还是说我应该直接用列表,然后逐个循环检查两个列表中的每个元素,确保另一个列表中有相同的元素呢?

2 个回答

2

我觉得最简单的方法就是用列表。

group_1 = my_dict_1.values()
group_2 = my_dict_2.values()

你的比较可能不会像考虑顺序或值可以哈希那样简单,但下面的方法应该可以用:

def contain_the_same(group_1, group_2):
    for item in group_1:
        if item not in group_2:
            return False
        else:
            group_2.pop(group_2.index(item))
    if len(group_2) != 0:
        return False
    return True

这个方法可以很好地处理那些不能哈希的对象:

>>> contain_the_same([1,2,3], [1,2,3])
True
>>> contain_the_same([1,2,3], [1,2,3,4])
False
>>> contain_the_same([1,2,[3,2,1]], [1,2,[3,2,1]])
True
>>> contain_the_same([5,1,2,[3,2,1,[1]]], [1,[3,2,1,[1]],2,5])
True

需要注意的是:如果一个列表里有重复的元素,而另一个列表没有,这个方法会返回假。这种情况下,如果你想允许重复元素,就需要做一些修改。

补充:其实还有更简单的方法:

sorted(my_dict_1.values()) == sorted(my_dict_1.values())

看起来这个方法的速度是我之前的 contain_the_same 函数的两倍:

>>> timeit("contain_the_same([5,1,2,[3,2,1,[1]]], [1,[3,2,1,[1]],2,5])", 
           "from __main__ import contain_the_same", number=10000)/10000
8.868489032757054e-06
>>>timeit("sorted([5,1,2,[3,2,1,[1]]]) == sorted([1,[3,2,1,[1]],2,5])",
           number=10000)/10000
4.928951884845034e-06

不过,这个方法在处理允许重复元素的情况下就没有那么简单了。

14

当没有重复项时,通常的选择有:

  1. 如果元素可以被哈希(简单来说,就是可以用来快速查找的):可以用 set(a) == set(b) 来比较。

  2. 如果元素可以排序:可以用 sorted(a) == sorted(b) 来比较。

  3. 如果你只关心是否相等:可以用 len(a) == len(b) and all(x in b for x in a) 来比较。

如果有重复项,并且重复的数量很重要,选择就变成:

  1. 如果元素可以被哈希:可以用 Counter(a) == Counter(b) 来比较,这样可以统计每个元素出现的次数。

  2. 如果元素可以排序:同样可以用 sorted(a) == sorted(b) 来比较。

  3. 如果你只关心是否相等:可以用 len(a) == len(b) and all(a.count(x) == b.count(x) for x in a) 来比较,这样会检查每个元素在两个列表中出现的次数是否相同。

撰写回答