Python:使用字典删除列表中的重复项并保持顺序

3

我有一个列表:

>>> a = big_list(30)
>>> a
[-14, -13, 10, 7, -10, 5, 3, 10, 8, -13, 14, -12, 6, 10, 8, 7, 4, -8, -10, -3, -6, 2, -6, 3, -3, 0, -13, -14, 2, -12]

我需要使用字典来保留顺序并从中删除重复项。

到目前为止,我使用了以下代码将a转换为字典:

def only_once(a):
    i = iter(a)
    print dict(zip(i,i))

输出结果为:
>>> only_once(a)
{2: -12, 3: 10, 4: -8, 6: 10, 8: 7, 10: 7, 14: -12, -14: -13, -13: -14, -10: -3, -6: 3, -3: 0}

有重复项且排列顺序奇怪,有什么方法可以将其转换为列表并保持顺序并删除重复项?


1
请查看http://docs.python.org/2/library/itertools.html#recipes和`unique_everseen`配方。如果您只是要删除重复项-您不需要将实际项目作为键/值对放置,就像您正在做的那样... - Jon Clements
如果期望的结果不是字典,那么就没有必要人为地使用字典。set 通常更适合处理重复项。 - Benjamin Toueg
5个回答

3

使用OrderedDict:

x = [-14, -13, 10, 7, -10, 5, 3, 10, 8, -13, 14, -12, 6, 10, 8, 7, 4, -8, -10, -3, -6, 2, -6, 3, -3, 0, -13, -14, 2, -12]
from collections import OrderedDict
d = OrderedDict.fromkeys(x)
x = list(d)

在这里,顺序是得到保留的,因为每个重复项的第一次出现仍然在相同的位置。


1
我不认为 OP 需要 iter,而且在这段代码中两次使用 iter(x) 是没有意义的 - 它总是只是 x... 另外,不需要使用 .keys() - 只需使用 list(d) - Jon Clements
1
不需要使用zip,只需使用OrderedDict.fromkeys。但如果这是答案,那么这个问题就是右侧链接的许多问题的重复。 - DSM

2
d = {e: i for i, e in enumerate (a) }
a = [x for x, _ in sorted(d.items (), key = lambda x: x [1] ) ]

当一个项目在原始列表中出现多次时,保留它的最后一次出现。

1
字典不存储顺序。如果您想仅使用纯字典完成您正在尝试的操作,则还需要在字典中存储列表中的位置。
def only_once(a):
    d = dict((b,a) for (a,b) in enumerate(a))
    new = d.items()
    return [x[0] for x in sorted(new, key=lambda a: a[1])]

这将创建一个字典,其中键是元素,值是列表中的位置,这意味着元素的第一次出现将被后续出现覆盖(调用 reversed() 以切换此行为)。然后,将从字典中提取(key,value)对,按列表中的位置排序,并截断为仅包含元素。

only_once ([1,1,1,3,3,2,2]) 的结果是 [0, 1, 2, 5, 6, 3, 4] - Hyperboreus

0

由于您没有指定字典需要如何使用,而且代码也不需要高效,我猜这个问题有很多可能的答案。例如,可以使用索引。

first_index = {v: len(a) - 1 - i for i, v in enumerate(reversed(a))}
print [v for i, v  in enumerate(a) if i == first_index[v]]

(我假设您想要删除列表中后面出现的重复项,同时保留第一次出现的项。)

-1
创建一个包含你要保留的物品的集合,并且丢弃你已经保留过的物品:
>>> a = [-14, -13, 10, 7, -10, 5, 3, 10, 8, -13, 14, -12, 6, 10, 8, 7, 4, -8, -10, -3, -6, 2, -6, 3, -3, 0, -13, -14, 2, -12]
>>> s = set()
>>> [ item for item in a if item not in s and s.add(item) == None]
[-14, -13, 10, 7, -10, 5, 3, 8, 14, -12, 6, 4, -8, -3, -6, 2, 0]

可以使用字典代替set,但这非常不自然:
>>> d = {}
>>> [ item for item in a if item not in d and d.update({item:None}) == None]
[-14, -13, 10, 7, -10, 5, 3, 8, 14, -12, 6, 4, -8, -3, -6, 2, 0]

很不幸,这非常低效(O(n^2))。它在每次迭代中都会对列表进行切片(O(n)),并且会线性搜索该项(每个迭代另外O(n))。 - nneonneo
改为O(n)解决方案。 - Benjamin Toueg
1
问题说明解决方案应使用字典。 - Stuart
1
如果期望的结果不是字典,就没有必要人为地使用字典。此外,set可以转换成字典。 - Benjamin Toueg
虽然我同意这种需求是人为的,但考虑到 OP 上一个问题是如何使用“set”来完成这个任务,我相信我们只是在帮助 OP 解决作业问题。 - DSM
我理解这一点,这就是为什么我添加了一个使用字典的解决方案。 - Benjamin Toueg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接