簡體   English   中英

Python:從列表中刪除特定項目的重復項

[英]Python: Remove duplicates for a specific item from 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

解決方案:

[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測試0 in mylist

如果性能是一個問題,並且您樂意使用第三方庫,請使用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

這聽起來像是一個更好的數據結構,你可以使用collections.Counter (在標准庫中):

import collections

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

這是一個基於生成器的方法,具有大約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])

切片應該做

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]

你可以用這個:

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

您現在可以更改所需的值,也可以將其設為這樣的列表

desired_value = [0, 6]
mylist = [i for i in mylist if i not in desired_value] + desired_value

也許你可以使用filter

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

你可以使用一個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]

這里是它的在線:其中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]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM