【问题标题】:Python: Generating a "set of tuples" from a "list of tuples" that doesn't take order into considerationPython:从不考虑顺序的“元组列表”生成“元组集”
【发布时间】:2016-03-07 06:05:09
【问题描述】:

如果我有如下的元组列表:

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

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

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

或者

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

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

【问题讨论】:

  • ... 将所有项目放在一个集合中,然后从集合条目中创建一个列表 - 这可能以前被问过
  • 你的问题是('a','b') != ('b','a'),或者更具体地说,hash(('a','b')) != hash(('b','a'))。做一个初始列表理解,对每个元组进行排序,然后转换为一个集合
  • 另外,您可能应该改写您的问题,因为“在内容和内部项目顺序方面重复”意味着您希望 ('a','b')('b','a') 不相等......

标签: python list tuples


【解决方案1】:

试试这个:

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')]

等等!

请注意,您可以使用generator 而不是list comprehension,跳过创建中间列表b

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

【讨论】:

  • 很好,只是您不需要实际创建中间列表set([ tuple(sorted(t)) for t in a ])set(tuple(sorted(t)) for t in a) 代替。
  • 没错,这不是 OP 要求。但他希望得到像[('a', 'b'), ('c', 'd')] 这样的输出,所以我认为它必须是一个列表。
  • 最终形式必须是列表;中间列表理解是不必要的。
  • 好的,我明白你的意思了。你说得对。我会保持我的答案不变,因为它更容易分解。 :)
  • 这在这种情况下不起作用:[('b','a'), ('c','d'), ('b','a')]。输出应为[('b','a'), ('c','d')],但您的代码输出[('a','b'), ('c','d')]。与其他元组比较时,元组中的顺序无关紧要——但输出应该包含原始元组——而不是修改后的元组。
【解决方案2】:

如果您不介意将 freezeset 与 set 一起使用:

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))

【讨论】:

    【解决方案3】:

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

    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')]
    

    【讨论】:

    • 我喜欢这个解决方案,因为它不对元组的长度或原始内部顺序做任何假设。
    • @PadraicCunningham,实际上前一个还可以。哈哈。我只是更喜欢你的,因为它喜欢速记,但我没有注意到它不会对列表元素进行排序,而是对列表本身进行排序。
    • 是的意思是a = map(tuple, map(sorted, l)),如果是python2那么imap会更好
    【解决方案4】:

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

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

    # 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) 这样的项目,因为它们分别相当于 (1,2,2) 和 (1,4,8) .
    为此,我们可以在原始数组中的每个元组上使用一个名为 filtered 或其他名称的新空列表和 itertools.permutations()
    首先,我们检查 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% 了解的是这样做的时间/空间复杂性——如果有人有反馈,我很想听听。

    【讨论】:

      【解决方案5】:

      内置类型的救援:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-03-15
        • 2013-11-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多