Python:从列表中删除特定项目的重复项

时间:2018-04-07 12:29:36

标签: python python-3.x list

我有一个项目列表,我想删除一个项目的任何重复项的出现,但保留其余的重复项。 即我从以下列表开始

mylist = [4, 1, 2, 6, 1, 0, 9, 8, 0, 9]

我想删除0的所有重复项,但保留19的重复项。 我目前的解决方案如下:

mylist = [i for i in mylist if i != 0]
mylist.add(0)

除了以下内容之外,还有一种方法可以保留0一次吗?

for i in mylist:
    if mylist.count(0) > 1:
        mylist.remove(0)

第二种方法需要的时间是这个例子的两倍多。

澄清:

  • 目前,我并不关心列表中项目的顺序,因为我目前在创建和清理后对其进行排序,但这可能会在以后更改。

  • 目前,我只需删除一个特定项目的重复项(在我的示例中为0

9 个答案:

答案 0 :(得分:2)

解决方案:

[0] + [i for i in mylist if i]

看起来不错,除非0不在mylist,但在这种情况下,您错误地添加了0。

此外,添加这样的2个列表并不是非常好的性能。我做了:

newlist = [i for i in mylist if i]
if len(newlist) != len(mylist):  # 0 was removed, add it back
   newlist.append(0)

(或使用过滤器newlist = list(filter(None,mylist)),因为没有本机python循环,所以可能会稍快一些)

在最后一个位置附加到列表非常有效(list对象使用预分配,大多数时候没有内存被复制)。长度测试技巧是O(1),允许避免测试0 in mylist

答案 1 :(得分:1)

如果性能有问题且您乐意使用第三方库,请使用numpy

Python标准库非常适合很多东西。数值数组的计算不是其中之一。

import numpy as np

mylist = np.array([4, 1, 2, 6, 1, 0, 9, 8, 0, 9])

mylist = np.delete(mylist, np.where(mylist == 0)[0][1:])

# array([4, 1, 2, 6, 1, 0, 9, 8, 9])

这里np.delete的第一个参数是输入数组。第二个参数提取所有出现的0的索引,然后从第二个实例开始提取。

效果基准

在Python 3.6.2 / Numpy 1.13.1上测试。性能将是系统和阵列特定的。

%timeit jp(myarr.copy())         # 183 µs
%timeit vui(mylist.copy())       # 393 µs
%timeit original(mylist.copy())  # 1.85 s

import numpy as np
from collections import Counter

myarr = np.array([4, 1, 2, 6, 1, 0, 9, 8, 0, 9] * 1000)
mylist = [4, 1, 2, 6, 1, 0, 9, 8, 0, 9] * 1000

def jp(myarr):
    return np.delete(myarr, np.where(myarr == 0)[0][1:])

def vui(mylist):
    return [0] + list(filter(None, mylist))

def original(mylist):
    for i in mylist:
        if mylist.count(0) > 1:
            mylist.remove(0)

    return mylist

答案 2 :(得分:1)

这听起来像是一个更好的数据结构供你使用collections.Counter(在标准库中):

import collections

counts = collections.Counter(mylist)
counts[0] = 1
mylist = list(counts.elements())

答案 3 :(得分:1)

这是一种基于生成器的方法,其复杂度大约为O(n),也保留了原始列表的顺序:

In [62]: def remove_dup(lst, item):
    ...:     temp = [item]
    ...:     for i in lst:
    ...:         if i != item:
    ...:             yield i
    ...:         elif i == item and temp:
    ...:             yield temp.pop()
    ...:             

In [63]: list(remove_dup(mylist, 0))
Out[63]: [4, 1, 2, 6, 1, 0, 9, 8, 9]

此外,如果您正在处理更大的列表,您可以使用Numpy使用以下矢量化和优化方法:

In [80]: arr = np.array([4, 1, 2, 6, 1, 0, 9, 8, 0, 9])

In [81]: mask = arr == 0

In [82]: first_ind = np.where(mask)[0][0]

In [83]: mask[first_ind] = False

In [84]: arr[~mask]
Out[84]: array([4, 1, 2, 6, 1, 0, 9, 8, 9])

答案 4 :(得分:1)

切片应该

a[start:end] # items start through end-1
a[start:]    # items start through the rest of the list
a[:end]      # items from the beginning through end-1
a[:]         # a copy of the whole list

输入:

mylist = [4,1, 2, 6, 1, 0, 9, 8, 0, 9,0,0,9,2,2,]
pos=mylist.index(0)
nl=mylist[:pos+1]+[i  for i in mylist[pos+1:] if i!=0]

print(nl)

输出:[4, 1, 2, 6, 1, 0, 9, 8, 9, 9, 2, 2]

答案 5 :(得分:1)

您可以使用:

CREATE EXTENSION IF NOT EXISTS earthdistance CASCADE;

您现在可以更改所需的值, 你也可以把它作为这样的列表

desired_value = 0
mylist = [i for i in mylist if i!=desired_value] + [desired_value]

答案 6 :(得分:0)

也许您可以使用filter

[0] + list(filter(lambda x: x != 0, mylist))

答案 7 :(得分:0)

您可以使用itertools.count计数器 这将返回0,1,......每次迭代时:

from itertools import count

mylist = [4, 1, 2, 6, 1, 0, 9, 8, 0, 9]

counter = count()

# next(counter) will be called each time i == 0
# it will return 0 the first time, so only the first time
# will 'not next(counter)' be True
out = [i for i in mylist if i != 0 or not next(counter)]
print(out)

# [4, 1, 2, 6, 1, 0, 9, 8, 9]

保留订单,并且可以轻松修改订单以对任意数量的值进行重复数据删除:

from itertools import count

mylist = [4, 1, 2, 6, 1, 0, 9, 8, 0, 9]

items_to_dedup = {1, 0}
counter = {item: count() for item in items_to_dedup}

out = [i for i in mylist if i not in items_to_dedup or not next(counter[i])]
print(out)

# [4, 1, 2, 6, 0, 9, 8, 9]

答案 8 :(得分:-1)

这里就行了:其中m是要发生一次的号码,并保留订单

[x for i,x in enumerate(mylist) if mylist.index(x)==i or x!=m]

<强>结果

[4, 1, 2, 6, 1, 0, 9, 8, 9]