我如何检查一个列表是否有任何重复,并返回一个没有重复的新列表?
当前回答
您可以使用以下函数:
def rem_dupes(dup_list):
yooneeks = []
for elem in dup_list:
if elem not in yooneeks:
yooneeks.append(elem)
return yooneeks
例子:
my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']
用法:
rem_dupes(my_list)
[‘这个’,‘是’,‘“,“列表”,“与”,“dupicates”,“在”,“的”)
其他回答
为了完整起见,由于这是一个非常流行的问题,toolz库提供了一个独特的函数:
>>> tuple(unique((1, 2, 3)))
(1, 2, 3)
>>> tuple(unique((1, 2, 1, 3)))
(1, 2, 3)
在Python 2.7中,从可迭代对象中删除重复项同时保持其原始顺序的新方法是:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
在Python 3.5中,OrderedDict有一个C实现。我的计时显示,这是Python 3.5的各种方法中最快和最短的。
在Python 3.6中,常规字典变得既有序又紧凑。(此特性适用于CPython和PyPy,但在其他实现中可能不存在)。这为我们提供了一种新的最快的方法,在保持秩序的同时减少数据:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
在Python 3.7中,常规字典保证在所有实现中都是有序的。所以,最短最快的解决方案是:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
在这个答案中,将有两个部分:两个唯一的解,和一个特定解的速度图。
删除重复项
这些答案大多只删除可哈希的重复项,但这个问题并不意味着它不需要可哈希项,这意味着我将提供一些不需要可哈希项的解决方案。
集合。Counter是标准库中的一个功能强大的工具,可以完美地实现这一点。只有另一种解决方案里面有Counter。然而,该解决方案也仅限于可哈希键。
为了在Counter中允许不可哈希键,我创建了一个Container类,它将尝试获取对象的默认哈希函数,但如果失败,它将尝试其标识函数。它还定义了一个eq和一个散列方法。这应该足以在我们的解决方案中允许不可散列项。不可哈希对象将被视为可哈希对象。但是,这个哈希函数对不可哈希对象使用identity,这意味着两个相等的不可哈希对象将不起作用。我建议您重写它,并将其更改为使用等效可变类型的哈希(例如,如果my_list是一个列表,则使用hash(tuple(my_list))。
我也得到了两个解。另一个解决方案是保持条目的顺序,使用OrderedDict和Counter的子类,命名为'OrderedCounter'。下面是函数:
from collections import OrderedDict, Counter
class Container:
def __init__(self, obj):
self.obj = obj
def __eq__(self, obj):
return self.obj == obj
def __hash__(self):
try:
return hash(self.obj)
except:
return id(self.obj)
class OrderedCounter(Counter, OrderedDict):
'Counter that remembers the order elements are first encountered'
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
def __reduce__(self):
return self.__class__, (OrderedDict(self),)
def remd(sequence):
cnt = Counter()
for x in sequence:
cnt[Container(x)] += 1
return [item.obj for item in cnt]
def oremd(sequence):
cnt = OrderedCounter()
for x in sequence:
cnt[Container(x)] += 1
return [item.obj for item in cnt]
Remd为非有序排序,oremd为有序排序。你可以清楚地看出哪个更快,但我还是会解释的。非有序排序稍微快一些,因为它不存储条目的顺序。
现在,我还想展示每个答案的速度比较。我现在就做。
哪个函数是最快的?
为了去除重复,我从几个答案中收集了10个函数。我计算了每个函数的速度,并使用matplotlib.pyplot将其放入一个图形中。
我把它分成三轮画图。hashable是任何可以哈希的对象,unhashable是任何不能哈希的对象。有序序列是保持有序的序列,无序序列不保持有序。现在,这里有更多的术语:
Unordered Hashable适用于任何删除重复项的方法,它不一定要保持顺序。它不需要为不可hashables工作,但它可以。
Ordered Hashable适用于任何保持列表中元素顺序的方法,但它不一定适用于unhashables,但它可以。
Ordered Unhashable是任何保持列表中项目顺序的方法,适用于unhashables。
y轴是花费的秒数。
x轴是函数作用的数字。
我用以下理解为无序哈希和有序哈希生成序列:[list(range(x)) + list(range(x)) for x in range(0,1000,10)]
对于有序的不可哈希对象:[[list(range(y)) + list(range(y)) For y in range(x)] For x in range(0,1000,10)]
请注意,在范围内有一个步骤,因为如果没有它,这将花费10倍的时间。也因为在我个人看来,我认为它可能看起来更容易阅读。
还要注意,图例上的键是我试图猜测的函数实现中最重要的部分。至于哪个功能是最好的还是最差的呢?图表说明了一切。
解决了这个问题,下面是图表。
无序Hashables
(放大)
命令Hashables
(放大)
命令Unhashables
(放大)
也有使用Pandas和Numpy的解决方案。它们都返回numpy数组,所以如果你想要一个列表,你必须使用.tolist()函数。
t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']
熊猫的解决方案
唯一使用Pandas函数():
import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']
Numpy解决方案
使用numpy函数unique()。
import numpy as np
np.unique(t).tolist()
>>>['a','b','c']
np.unique(t2).tolist()
>>>['a','b','c']
注意,numpy.unique()也对值进行排序。所以列表t2是有序返回的。如果你想保留顺序,可以这样回答:
_, idx = np.unique(t2, return_index=True)
t2[np.sort(idx)].tolist()
>>>['c','b','a']
与其他解决方案相比,该解决方案并不那么优雅,但是,与pandas.unique()相比,numpy.unique()还允许您检查嵌套数组在选定的轴上是否唯一。
减少变量与顺序保存:
假设我们有一个列表:
l = [5, 6, 6, 1, 1, 2, 2, 3, 4]
减少变体(无效):
>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]
5倍快,但更复杂
>>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
[5, 6, 1, 2, 3, 4]
解释:
default = (list(), set())
# user list to keep order
# use set to make lookup faster
def reducer(result, item):
if item not in result[1]:
result[0].append(item)
result[1].add(item)
return result
reduce(reducer, l, default)[0]
推荐文章
- Numpy Max vs amax vs maximum
- 我应该在.gitignore文件中添加Django迁移文件吗?
- 每n行有熊猫
- 实例属性attribute_name定义在__init__之外
- 使嵌套JavaScript对象平放/不平放的最快方法
- 如何获取在Python中捕获的异常的名称?
- 第一次出现的值大于现有值的Numpy
- 大的Ө符号到底代表什么?
- 如何从Python函数中返回两个值?
- 前一个月的Python日期
- Python中方括号括起来的列表和圆括号括起来的列表有什么区别?
- Python日志记录不输出任何东西
- 堆与二叉搜索树(BST)
- 每n秒运行特定代码
- 给定一个数字数组,返回所有其他数字的乘积的数组(不除法)