如何根据元组的索引值从列表中删除重复的元组,同时保持元组的顺序? [复制]

Posted

技术标签:

【中文标题】如何根据元组的索引值从列表中删除重复的元组,同时保持元组的顺序? [复制]【英文标题】:How can I remove duplicate tuples from a list based on index value of tuple while maintaining the order of tuple? [duplicate] 【发布时间】:2018-09-27 13:24:17 【问题描述】:

我想删除那些在索引 0 处具有相同值的元组,但第一次出现除外。我查看了其他类似的问题,但没有得到我正在寻找的特定答案。有人能帮帮我吗? 以下是我尝试过的。

from itertools import groupby
import random
Newlist = []

abc = [(1,2,3), (2,3,4), (1,0,3),(0,2,0), (2,4,5),(5,4,3), (0,4,1)]

Newlist = [random.choice(tuple(g)) for _, g in groupby(abc, key=lambda x: x[0])]
print Newlist

我的预期输出:[(1,2,3), (2,3,4), (0,2,0), (5,4,3)]

【问题讨论】:

有了random.choice,你的尝试如何保证它只保留第一次出现? 【参考方案1】:

要正确使用groupby,必须对序列进行排序:

>>> [next(g) for k,g in groupby(sorted(abc, key=lambda x:x[0]), key=lambda x:x[0])]
[(0, 2, 0), (1, 2, 3), (2, 3, 4), (5, 4, 3)]

或者如果您需要示例的非常精确的顺序(即保持原始顺序):

>>> [t[2:] for t in sorted([next(g) for k,g in groupby(sorted([(t[0], i)+t for i,t in enumerate(abc)]), lambda x:x[0])], key=lambda x:x[1])]
[(1, 2, 3), (2, 3, 4), (0, 2, 0), (5, 4, 3)]

这里的诀窍是添加一个字段以在 groupby() 步骤之后保持原始顺序恢复。

编辑:甚至更短一点:

>>> [t[1:] for t in sorted([next(g)[1:] for k,g in groupby(sorted([(t[0], i)+t for i,t in enumerate(abc)]), lambda x:x[0])])]
[(1, 2, 3), (2, 3, 4), (0, 2, 0), (5, 4, 3)]

【讨论】:

确实如此,但问题是关于维护元组的顺序。我认为没有使用 groupby 的解决方案 @fferri:我需要元组的顺序,如预期输出所示。 @A.S 我更新了我的答案 @PatrickHaugh:任何工具都有解决方案=P @fferri:感谢您付出的额外努力。现在可以了。【参考方案2】:

使用OrderedDict 的更好选择:

from collections import OrderedDict

abc = [(1,2,3), (2,3,4), (1,0,3), (0,2,0), (2,4,5),(5,4,3), (0,4,1)]
d = OrderedDict()
for t in abc:
    d.setdefault(t[0], t)
abc_unique = list(d.values())
print(abc_unique)

输出:

[(1, 2, 3), (2, 3, 4), (0, 2, 0), (5, 4, 3)]

简单但效率不高:

abc = [(1,2,3), (2,3,4), (1,0,3), (0,2,0), (2,4,5),(5,4,3), (0,4,1)]
abc_unique = [t for i, t in enumerate(abc) if not any(t[0] == p[0] for p in abc[:i])]
print(abc_unique)

输出:

[(1, 2, 3), (2, 3, 4), (0, 2, 0), (5, 4, 3)]

【讨论】:

@jdehesa:谢谢,它有效。【参考方案3】:

一种简单的方法是遍历列表并跟踪您已经找到的元素:

abc = [(1,2,3), (2,3,4), (1,0,3),(0,2,0), (2,4,5),(5,4,3), (0,4,1)]
found = set()
NewList = []
for a in abc:
    if a[0] not in found:
        NewList.append(a)
    found.add(a[0])
print(NewList)
#[(1, 2, 3), (2, 3, 4), (0, 2, 0), (5, 4, 3)]

foundset。在每次迭代中,我们检查元组中的第一个元素是否已经在found 中。如果没有,我们将整个元组附加到NewList。在每次迭代结束时,我们将元组的第一个元素添加到 found

【讨论】:

一个警告是,这仅在元组的第一个元素是可散列的情况下才有效(当然,如给定示例中的数字是)。 轻微改进:仅在found 中不存在的情况下将a[0] 添加到found(即将found.add(a[0]) 的缩进增加一级)。 如果a[0]foundcontinue 会更好,否则追加/添加(如@JackTaylor 所述,没有缩进问题) 谢谢@pault:我在我的代码上使用了这个解决方案。【参考方案4】:

itertools recipes(Python 2:itertools recipes,但在这种情况下基本上没有区别)包含一个方法,它比@pault 的implementation 更通用一点。它还使用set

Python 2:

from itertools import ifilterfalse as filterfalse

Python 3:

from itertools import filterfalse
def unique_everseen(iterable, key=None):
    "List unique elements, preserving order. Remember all elements ever seen."
    # unique_everseen('AAAABBBCCDAABBB') --> A B C D
    # unique_everseen('ABBCcAD', str.lower) --> A B C D
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in filterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element

使用它:

abc = [(1,2,3), (2,3,4), (1,0,3),(0,2,0), (2,4,5),(5,4,3), (0,4,1)]
Newlist = list(unique_everseen(abc, key=lambda x: x[0]))
print Newlist
# [(1, 2, 3), (2, 3, 4), (0, 2, 0), (5, 4, 3)]

这应该稍微快一些,因为 set.add 方法的缓存(仅当您的 abc 很大时才真正相关)并且还应该更通用,因为它使 key 函数成为参数。

除此之外,我在评论中已经提到的相同限制适用:这仅适用于元组的第一个元素实际上是可散列的(当然,如给定示例中的数字是)。

【讨论】:

@A.S 已修复。在 Python 2 中,它被称为 ifilterfalse。它仍然有效,因为在这种情况下定义了 key 函数。【参考方案5】:

@PatrickHaugh 声称:

但问题显然是关于维护 元组。我认为没有使用 groupby 的解决方案

我从不错过 (ab) 使用 groupby() 的机会。这是我的无排序解决方案(一次或两次):

from itertools import groupby, chain

abc = [(1, 2, 3), (2, 3, 4), (1, 0, 3), (0, 2, 0), (2, 4, 5), (5, 4, 3), (0, 4, 1)]

Newlist = list((lambda s: chain.from_iterable(g for f, g in groupby(abc, lambda k: s.get(k[0]) != s.setdefault(k[0], True)) if f))())

print(Newlist)

输出

% python3 test.py
[(1, 2, 3), (2, 3, 4), (0, 2, 0), (5, 4, 3)]
%

【讨论】:

以上是关于如何根据元组的索引值从列表中删除重复的元组,同时保持元组的顺序? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

使用python从不同长度的元组列表中删除重复项

根据元组的值对元组列表中的重复元组进行平均

如何从python中的列表中删除重复的元组?

Python中的元组(Tuple)

在元组的ndarray中查找元组并返回搜索到的元组的索引

如何从具有子元组的元组创建列表?