从 python 集中获取唯一的元组
Getting unique tuples out of a python set
我目前有如下一组:
{(a,b), (b,a), (c,b), (b,c)}
我想要的是:
{(a,b), (c,b)}
您可能会注意到重复值已被完全删除,因此无论顺序如何,两个元组都不会包含相同的元素。
如何让集合忽略元组中元素的顺序,只检查元组之间的值?
相当丑陋,直接的解决方案。您实施平等将 (2, 3)
和 (3, 2)
视为平等对象,您实施 __hash__
以禁止集合中的平等成员。您可以按照以下断言访问成员。
我对散列函数的外观不满意,但无论如何 - 这只是概念证明。希望您会找到更优雅的解决方案来计算它而不会发生碰撞。
class WhateverItIs(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __eq__(self, other):
return ((self.a == other.a and self.b == other.b) or
(self.a == other.b and self.b == other.a))
def __hash__(self):
return hash(tuple(sorted((self.a, self.b))))
o1 = WhateverItIs(2, 3)
o2 = WhateverItIs(3, 2)
o3 = WhateverItIs(4, 3)
assert {o1, o2, o3} in [{o1, o3}, {o2, o3}]
assert o1 == o2
assert o1.a == 2
assert o1.b == 3
assert o2.a == 3
assert o2.b == 2
assert o3.a == 4
assert o3.b == 3
好的,所以你有一个集合 {c1, c2, c3, ...}
,其中每个 cN
本身就是某种集合。
如果您不关心 cN
中元素的顺序,但关心它是唯一的(无视顺序),那么 cN
应该是 frozenset
1 而不是 tuple
:
>>> orig = {("a", "b"), ("b", "a"), ("c", "b"), ("b", "c")}
>>> uniq = {frozenset(c) for c in orig}
>>> uniq
{frozenset(['b', 'a']), frozenset(['b', 'c'])}
作为一般规则,从 Python 提供的数据类型中选择合适的数据类型比定义和维护自定义 类 更直接。
1 它不能是 set
,因为作为更大的 set
的成员它需要是可哈希的。
>>> aa = [('a', 'b'), ('c', 'd'), ('b', 'a')]
>>> seen = set()
>>> a = [seen.add((x,y)) for x,y in aa if (x,y) and (y,x) not in seen ]
>>> list(seen)
[('a', 'b'), ('c', 'd')]
您可以做的一件简单的事情就是简单地对每个 tuple
元素进行排序(这使得 tuple
成为 list
),然后转换为 tuple
,允许将其添加到集合中并维护 tuple
.
的 "hashable type"
示例:
>>> a = 1
>>> b = 2
>>> c = 3
>>> set_to_add_tuples_to = set()
>>> tuples_to_add_to_set = [(a,b), (b,a), (c,b), (b,c)]
>>> print(tuple_to_add_to_set)
[(1, 2), (2, 1), (3, 2), (2, 3)]
>>> for tup in tuples_to_add_to_set:
... tup = tuple(sorted(tup))
... set_to_add_tuples_to.add(tup)
>>> print(set_to_add_tuples_to)
{(1, 2), (2, 3)}
我目前有如下一组:
{(a,b), (b,a), (c,b), (b,c)}
我想要的是:
{(a,b), (c,b)}
您可能会注意到重复值已被完全删除,因此无论顺序如何,两个元组都不会包含相同的元素。
如何让集合忽略元组中元素的顺序,只检查元组之间的值?
相当丑陋,直接的解决方案。您实施平等将 (2, 3)
和 (3, 2)
视为平等对象,您实施 __hash__
以禁止集合中的平等成员。您可以按照以下断言访问成员。
我对散列函数的外观不满意,但无论如何 - 这只是概念证明。希望您会找到更优雅的解决方案来计算它而不会发生碰撞。
class WhateverItIs(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __eq__(self, other):
return ((self.a == other.a and self.b == other.b) or
(self.a == other.b and self.b == other.a))
def __hash__(self):
return hash(tuple(sorted((self.a, self.b))))
o1 = WhateverItIs(2, 3)
o2 = WhateverItIs(3, 2)
o3 = WhateverItIs(4, 3)
assert {o1, o2, o3} in [{o1, o3}, {o2, o3}]
assert o1 == o2
assert o1.a == 2
assert o1.b == 3
assert o2.a == 3
assert o2.b == 2
assert o3.a == 4
assert o3.b == 3
好的,所以你有一个集合 {c1, c2, c3, ...}
,其中每个 cN
本身就是某种集合。
如果您不关心 cN
中元素的顺序,但关心它是唯一的(无视顺序),那么 cN
应该是 frozenset
1 而不是 tuple
:
>>> orig = {("a", "b"), ("b", "a"), ("c", "b"), ("b", "c")}
>>> uniq = {frozenset(c) for c in orig}
>>> uniq
{frozenset(['b', 'a']), frozenset(['b', 'c'])}
作为一般规则,从 Python 提供的数据类型中选择合适的数据类型比定义和维护自定义 类 更直接。
1 它不能是 set
,因为作为更大的 set
的成员它需要是可哈希的。
>>> aa = [('a', 'b'), ('c', 'd'), ('b', 'a')]
>>> seen = set()
>>> a = [seen.add((x,y)) for x,y in aa if (x,y) and (y,x) not in seen ]
>>> list(seen)
[('a', 'b'), ('c', 'd')]
您可以做的一件简单的事情就是简单地对每个 tuple
元素进行排序(这使得 tuple
成为 list
),然后转换为 tuple
,允许将其添加到集合中并维护 tuple
.
示例:
>>> a = 1
>>> b = 2
>>> c = 3
>>> set_to_add_tuples_to = set()
>>> tuples_to_add_to_set = [(a,b), (b,a), (c,b), (b,c)]
>>> print(tuple_to_add_to_set)
[(1, 2), (2, 1), (3, 2), (2, 3)]
>>> for tup in tuples_to_add_to_set:
... tup = tuple(sorted(tup))
... set_to_add_tuples_to.add(tup)
>>> print(set_to_add_tuples_to)
{(1, 2), (2, 3)}