Python:从不考虑顺序的"list of tuples"生成"set of tuples"



如果我有如下元组列表:

[('a', 'b'), ('c', 'd'), ('a', 'b'), ('b', 'a')]

我想删除重复的元组(在内容和内部项目顺序方面都是重复的(,以便输出为:

[('a', 'b'), ('c', 'd')]

[('b', 'a'), ('c', 'd')]

我尝试将其转换为 set 然后转换为列表,但输出将在结果集中保持('b', 'a')('a', 'b')

试试这个:

a = [('a', 'b'), ('c', 'd'), ('a', 'b'), ('b', 'a')]
b = list(set([ tuple(sorted(t)) for t in a ]))
[('a', 'b'), ('c', 'd')]

让我们分解一下:

如果对元组进行排序,它将变为排序列表。

>>> t = ('b', 'a')
>>> sorted(t)
['a', 'b']

对于a中的每个元组t,对其进行排序并将其转换回元组。

>>> b = [ tuple(sorted(t)) for t in a ]
>>> b
[('a', 'b'), ('c', 'd'), ('a', 'b'), ('a', 'b')]

将结果列表b转换为集合:值现在是唯一的。将其转换回列表。

>>> list(set(b))
[('a', 'b'), ('c', 'd')]

瞧!

请注意,您可以使用生成器而不是列表推导式跳过中间列表b的创建。

>>> list(set(tuple(sorted(t)) for t in a))
[('a', 'b'), ('c', 'd')]

如果您不介意将冻结集与集合一起使用:

l = [('a', 'b'), ('c', 'd'), ('a', 'b'), ('b', 'a')]
print(set(map(frozenset,l)))
{frozenset({'a', 'b'}), frozenset({'c', 'd'})}

如果愿意,您可以转换回元组:

l = [('a', 'b'), ('c', 'd'), ('a', 'b'), ('b', 'a')]
print(list(map(tuple,set(map(frozenset ,l)))))
[('a', 'b'), ('d', 'c')]

或者使用集合并反转元组的顺序:

l = [('a', 'b'), ('c', 'd'), ('a', 'b'), ('b', 'a')]
seen, pairs = set(), []
for a,b in l:
    if (a,b) not in seen and (b,a) not in seen:
        pairs.append((a,b))
    seen.add((a,b))

如果顺序不重要,这可以解决您的问题。

a=[('a', 'b'), ('c', 'd'), ('a', 'b'), ('b', 'a')]

a=map(tuple,[sorted(i) for i in a])
print list(set(a))

输出:

[('a', 'b'), ('c', 'd')]

只是想添加一个潜在的第二个解决方案,如果有人有一个"先到先得"可能很重要的用例。

例如,假设我们获取三个列表并将它们合并到一个元组列表中:

# Make some lists (must be same size) 
a = [1,1,1,2,8,6,1]
b = [2,4,6,1,4,21,69]
c = [2,8,21,2,1,1,8]
# Lists to list of tuples
arr = []
for i in range(len(a)):
    new_row = (a[i],b[i],c[i])
    arr.append(new_row)

这样我们的原始数组看起来像:

(1, 2, 2)
(1, 4, 8)
(1, 6, 21)
(2, 1, 2)
(8, 4, 1)
(6, 21, 1)
(1, 69, 8)

在我们的例子中,我们希望删除像 (2,1,2( 和 (8,4,1( 这样的项目,因为它们><分别等同于 和=" filtered=" />首先,我们检查每个项目的排列是否存在于filtered列表中.
如果没有,我们添加。如果是,我们跳过重复项。

filtered = []
for i in range(len(arr)):
    it = itertools.permutations(arr[i])
    perms = []
    for p in it:
        perms.append(p)  
    check = any(item in perms for item in filtered)
    if not check: 
        filtered.append(arr[i])

现在,如果我们遍历filtered并打印,我们会看到截断的元组列表:

(1, 2, 2)
(1, 4, 8)
(1, 6, 21)
(1, 69, 8)

请注意,我们只剩下每个数字元组的第一个实例,并且不通过set工作可以保证在迭代过滤列表时元素的顺序相同。

我唯一不是100%的就是这样做的时间/空间复杂性 - 如果有人有反馈,我很想听听。

内置类型来救援:

data = [('a', 'b'), ('c', 'd'), ('a', 'b'), ('b', 'a')]
set(map(frozenset, data))
{frozenset({'a', 'b'}), frozenset({'c', 'd'})}

最新更新