Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 从列表中删除唯一值并仅保留重复值_Python - Fatal编程技术网

Python 从列表中删除唯一值并仅保留重复值

Python 从列表中删除唯一值并仅保留重复值,python,Python,我希望运行一个ID列表,并返回一个出现多次的ID列表。这就是我设置的工作: singles = list(ids) duplicates = [] while len(singles) > 0: elem = singles.pop() if elem in singles: duplicates.append(elem) 但是ids列表可能会变得很长,实际上,如果可以避免的话,我不希望在昂贵的len调用上进行while循环。(我可以走不雅观的路线,给le

我希望运行一个ID列表,并返回一个出现多次的ID列表。这就是我设置的工作:

singles = list(ids)
duplicates = []
while len(singles) > 0:
    elem = singles.pop()
    if elem in singles:
        duplicates.append(elem)

但是ids列表可能会变得很长,实际上,如果可以避免的话,我不希望在昂贵的len调用上进行while循环。(我可以走不雅观的路线,给len打一次电话,然后每次迭代都减少它,但如果可以的话,我宁愿避免这种情况)。

你可以这样做

>>> ids = [1,2,3,2,3,5]
>>> set(i for i in ids if ids.count(i) > 1)
{2, 3}

如果您不关心检索这些ID的顺序,那么一种有效的方法将包括一个排序步骤(即O(N log(N)),然后保留后面跟着的ID(即O(N))。因此,这种方法总体上是O(N log(N))。

我认为这会更快:

occasions = {}
for id in ids:
    try:
        occasions[id] += 1
    except KeyError:
        occasions[id] = 0
result = [id for id in ids if occasions[id] > 1]

要做到这一点,明智的方法是使用一种简单高效的数据结构,如:

构建
计数器
需要O(N)时间,而不是O(N log N)时间进行排序,或者O(N^2)时间用于每次从头开始计算每个元素


作为旁注:

但是ids列表可能会变得很长,实际上,如果可以避免的话,我不希望在昂贵的len调用上进行while循环

len
不贵。这是一个固定的时间,而且(至少在内置类型列表
list
)它的速度几乎与Python中的函数所能达到的速度一样快,根本不做任何事情


代码中代价高昂的部分是在循环中调用单元素中的元素,这意味着对于每个元素,您必须将其与其他元素进行比较,这意味着二次时间。

或使用
itertools.groupby

>>> l=[1,1,2,2,2,3]
>>> from itertools import groupby
>>> print([key for key,group in groupby(l) if len(list(group)) > 1])
[1, 2]
>>> 
只需检查组(在循环中)是否大于一,如果是,则保留它,否则不要

或使用熊猫:

>>> import pandas as pd
>>> s=pd.Series(l)
>>> s[s.duplicated()].unique().tolist()
[1, 2]
>>> 
它非常快,因为熊猫的速度非常快

文件:

将光标放在黄色部分以查看链接

,及


但是排序本身是O(N logn),所以O(N)步并不重要。另外,这破坏了顺序,我们不知道这是否可以接受,所以你不能仅仅假设它是可以接受的。是的,如果结果必须是相同的顺序,它是不起作用的。我认为使用
itertools.ifilter
会更有效。(我用
计数器和
ifilter
写了一个答案,但你写得更快;)@Kasra:为什么?使用
filter
/
ifilter
而不是生成器表达式/列表理解意味着您必须将测试包装在函数中,这会增加额外的成本。(如果你只是指如果我们不需要列表,就不要构建列表,更简单的方法是将listcomp更改为genexpr,但由于他明确表示需要返回列表,我认为你无法避免构建列表。)@Kasra:第一个列表只是创建测试数据。您需要从某个地方获取输入数据。@Kasra:无论如何,不要猜测,从对10000个具有100个唯一值的元素进行的快速测试来看,
[listcomp]
需要1.88ms,
list(genexpr)
需要2.25ms,
filter
需要2.71ms,
list(ifilter)
需要2.91ms。因此,使用
ifilter
可以使速度降低55%。无论如何,这种微观优化很少值得担心;一旦你从二次行为变为线性,通常你可以停止优化…为什么不
[i代表i,j计数.items(),如果j>1]
?如果你想以一个列表结束,只需要一个小的加法:duplicates=list(set(id中的i代表i,如果id.count(i)>1))
列表(set(id中的i代表i,如果id.count(i)>1))
这甚至比他现有的代码还要慢(尽管只有2-ish的常数因子)。它确实删除了
len
调用,但那部分并不重要;用ID.code
替换singles中的
元素
意味着您现在每次都在搜索每个元素,而不是只搜索重复项中的第一个匹配项。此外,这会破坏顺序,并将所有重复项压缩为1,而他的原始代码都没有这样做,所以我不认为这是可以接受的。是的,这基本上只是手动实现的
计数器的一个简单版本,所以速度也一样快。(或者至少非常接近;
计数器
使用
\uuuu missing\uuuu
而不是
,除了KeyError:
,可能会稍微快一点,但这只会产生一个小的恒定差异。)我认为
场合=计数器(ID)
更容易阅读,更难出错,但这也很好,特别是对于一个还不习惯用口述来思考为什么它有用的新手来说,这可能更清楚。好吧,我完全同意你的看法。谢谢你的回答,我不知道有这样一个功能。
>>> import pandas as pd
>>> s=pd.Series(l)
>>> s[s.duplicated()].unique().tolist()
[1, 2]
>>>