单行删除重复项,保持列表排序 [重复]

Posted

技术标签:

【中文标题】单行删除重复项,保持列表排序 [重复]【英文标题】:One-liner to remove duplicates, keep ordering of list [duplicate] 【发布时间】:2018-01-26 12:43:19 【问题描述】:

我有以下清单:

['Herb', 'Alec', 'Herb', 'Don']

我想在保持订单的同时删除重复项,所以它会是:

['Herb', 'Alec', 'Don']

下面是我详细说明的方法:

l_new = []
for item in l_old:
    if item not in l_new: l_new.append(item)

有没有办法在一行中做到这一点?

【问题讨论】:

@Dekel 我明白了,我的问题是寻找一个单线虽然可以做到这一点。 该问题的许多答案都有一个使用不同方法的衬线 【参考方案1】:

您可以使用集合来删除重复项,然后恢复排序。而且它和你原来的一样慢,耶:-)

>>> sorted(set(l_old), key=l_old.index)
['Herb', 'Alec', 'Don']

【讨论】:

哈!我觉得这个解决方案很有趣!它也启发了我......【参考方案2】:

您可以使用OrderedDict,但我建议坚持使用您的 for 循环。

>>> from collections import OrderedDict
>>> data = ['Herb', 'Alec', 'Herb', 'Don']
>>> list(OrderedDict.fromkeys(data))
['Herb', 'Alec', 'Don']

重申一下:我认真建议坚持你的 for 循环方法,并使用 set 来跟踪已经看到的项目:

>>> data = ['Herb', 'Alec', 'Herb', 'Don']
>>> seen = set()
>>> unique_data = []
>>> for x in data:
...     if x not in seen:
...         unique_data.append(x)
...         seen.add(x)
...
>>> unique_data
['Herb', 'Alec', 'Don']

如果你只是想变得古怪(千万不要这样做):

>>> [t[0] for t in sorted(dict(zip(reversed(data), range(len(data), -1, -1))).items(), key=lambda t:t[1])]
['Herb', 'Alec', 'Don']

【讨论】:

为什么你会建议反对上述内容? @David542 因为它效率低下且不明确。事实上,我怀疑几乎所有的单线都可以。 @StefanPochmann 我已经编辑明确包含我的意思暗示。 OrderedDict.fromkeys is a class method,不是吗?所以不需要创建OrderedDict 实例。 list(OrderedDict.fromkeys(data)) 会起作用。 @ChristianDean 是的,我犯了一个愚蠢的错误。感谢您指出。我想我最初开始写类似OrderedDict((k, None) for k in data) 的东西,然后就像,哦等等,.fromkeys已经存在......【参考方案3】:

使用 pandas,从列表中创建一个系列,删除重复项,然后将其转换回列表。

import pandas as pd

>>> pd.Series(['Herb', 'Alec', 'Herb', 'Don']).drop_duplicates().tolist()
['Herb', 'Alec', 'Don']

时间

@StefanPochmann 的解决方案显然是高重复列表的赢家。

my_list = ['Herb', 'Alec', 'Don'] * 10000

%timeit pd.Series(my_list).drop_duplicates().tolist()
# 100 loops, best of 3: 3.11 ms per loop

%timeit list(OrderedDict().fromkeys(my_list))
# 100 loops, best of 3: 16.1 ms per loop

%timeit sorted(set(my_list), key=my_list.index)
# 1000 loops, best of 3: 396 µs per loop

对于没有重复的较大列表(例如,只是一个数字范围),pandas 解决方案非常快。

my_list = range(10000)

%timeit pd.Series(my_list).drop_duplicates().tolist()
# 100 loops, best of 3: 3.16 ms per loop

%timeit list(OrderedDict().fromkeys(my_list))
# 100 loops, best of 3: 10.8 ms per loop

%timeit sorted(set(my_list), key=my_list.index)
# 1 loop, best of 3: 716 ms per loop

【讨论】:

如何适合你使用 pandas ;-) @ChristianDean 一个使用 pandas 的 pandas 开发者......令人震惊。 @StefanPochmann 你知道我说的是他的头像,对吧? @ChristianDean 我愿意,但我认为你搞错了。我认为这张照片适合他对熊猫的使用,而不是相反。 @Alexander 虽然我确实喜欢赢得一些东西,但我确实需要指出,您的测试用例对其他解决方案非常不公平(因为它对我来说非常不合理)。【参考方案4】:

如果你真的不关心优化和其他东西,你可以使用以下内容:

s = ['Herb', 'Alec', 'Herb', 'Don']
[x[0] for x in zip(s, range(len(s))) if x[0] not in s[:x[1]]]

请注意,我认为您确实应该在您的问题中使用for 循环或@juanpa.arrivillaga 的答案

【讨论】:

【参考方案5】:

你可以试试这个:

l = ['Herb', 'Alec', 'Herb', 'Don']
data = [i[-1] for i in sorted([(a:i for i, a in enumerate(l)[a], a) for a in set(a:i for i, a in enumerate(l).keys())], key = lambda x: x[0])]

输出:

['Alec', 'Herb', 'Don']

此算法仅删除重复值的第一个实例。

【讨论】:

【参考方案6】:
l_new = []
for item in l_old:
    if item not in l_new: l_new.append(item)

一行..ish:

l_new = []

[ l_new.append(item)  for item in l_old if item not in l_new]

有哪些行为:

> a = [1,1,2,2,3,3,4,5,5]
> b = []
> [ b.append(item) for item in a if item not in b]
> print(b)
[1,2,3,4,5]

【讨论】:

您的单行解决方案需要一个分号:l_new = []; [l_new.append(item) for item in l_old if item not in l_new] 但那是作弊:P 然后在内部理解。 @Erich 嗯?你已经在这样做了。与item。好的,这是一个方法:[l_new.append(item) or l_new for l_new in [[]] for item in l_old if item not in l_new][0] 啊,我明白了。我认为我必须创建一些超出理解范围的东西,但是你的空列表技巧非常酷:)

以上是关于单行删除重复项,保持列表排序 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

从未排序的链接列表中删除重复项

c_cpp 83.从排序列表中删除重复项

java 82.从排序列表II(递归).java中删除重复项

java 82.从排序列表II(递归).java中删除重复项

java 82.从排序列表II(递归).java中删除重复项

java 82.从排序列表II(递归).java中删除重复项