从包含不可混淆元素的Python列表中删除重复元素,同时保留顺序?

时间:2011-11-01 22:56:04

标签: python

我有这样的数据结构:

[
[('A', '1'), ('B', '2')],
[('A', '1'), ('B', '2')],
[('A', '4'), ('C', '5')]
]

我想得到这个:

[
[('A', '1'), ('B', '2')],
[('A', '4'), ('C', '5')]
]

有没有一种很好的方法可以在保持秩序的同时执行此操作?

用于复制粘贴的命令:

sample = []
sample.append([('A', '1'), ('B', '2')])
sample.append([('A', '1'), ('B', '2')])
sample.append([('A', '4'), ('C', '5')])

2 个答案:

答案 0 :(得分:7)

这是一个有点着名的问题,很久以前一个着名的Pythonista已经很好地回答了这个问题:http://code.activestate.com/recipes/52560-remove-duplicates-from-a-sequence/

如果您可以假设相同的记录是相邻的,则itertools docs中有一个食谱:

from operator import itemgetter
from itertools import groupby, imap

def unique_justseen(iterable, key=None):
    "List unique elements, preserving order. Remember only the element just seen."
    # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
    # unique_justseen('ABBCcAD', str.lower) --> A B C A D
    return imap(next, imap(itemgetter(1), groupby(iterable, key)))

如果您只能假定可订购元素,这里使用bisect模块的变体。给定具有 r 唯一值的 n 输入,其搜索步骤花费O(n log r)。如果找到新的唯一值,则会将其插入看到的列表中,费用为O(r * r)。

from bisect import bisect_left, insort

def dedup(seq):
    'Remove duplicates. Preserve order first seen.  Assume orderable, but not hashable elements'
    result = []
    seen = []
    for x in seq:
        i = bisect_left(seen, x)
        if i == len(seen) or seen[i] != x:
            seen.insert(i, x)
            result.append(x)
    return result

答案 1 :(得分:5)

这是排序/唯一惯用语的保留顺序的变体。如果您的项目至少可以排序,这将为您提供O(n log n)性能。

def unique(a):
    indices = sorted(range(len(a)), key=a.__getitem__)
    indices = set(next(it) for k, it in 
                  itertools.groupby(indices, key=a.__getitem__))
    return [x for i, x in enumerate(a) if i in indices]

示例(为简单起见,带有可清洗物品):

>>> a = ['F', 'J', 'B', 'F', 'V', 'A', 'E', 'U', 'B', 'U', 'Z', 'K']
>>> unique(a)
['F', 'J', 'B', 'V', 'A', 'E', 'U', 'Z', 'K']