2017-08-09 82 views
2

我有號碼的列表,例如:如何在python中刪除?

l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,0,0,0,0] 

我想知道的是,有多少主導價值觀,我需要去取全零的名單?

所以這裏的答案是4

我在想,反轉列表,然後使用for循環和計數器來運行列表,直到找到第一個非零元素,然後減去計數器和列表長度,但它看起來有點難看。

有沒有一個很好的'pythonic'方法來做到這一點?

(編輯爲清楚:

l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0] 

應該去11,所以我不能只是使用過濾器,我想知道的製片人花了多長時間安定下來的地步輸出連續變。零)

+1

它會一直是這樣的情況,最終0會混亂嗎? –

+4

因此,你的最終結果應該輸出一些你需要刪除的數量,以便列表中滿爲零?你的清單是否總是按這種方式訂購?是否會出現零之間不爲零的情況? – idjaw

+3

'sum(1 for x in l if x!= 0)'? –

回答

5

您可以使用itertools.dropwhileitertools.takewhile對於這樣的:如果有零點

>>> l = [0.01,0.02,0.01,-0.01,0,0,0,0,0,0,0,0,0,0] 
>>> import itertools 
>>> list(itertools.dropwhile(lambda x: x != 0, l)) 
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
>>> list(itertools.takewhile(lambda x: x != 0, l)) 
[0.01, 0.02, 0.01, -0.01] 
>>> sum(1 for _ in itertools.takewhile(lambda x: x != 0, l)) 
4 

但是,如果你想在列表中只包含0,然後從前下探可能無法正常工作然後再次非零元素。相反,你最好從最後開始,使用reversed,直到找到第一個非零元素。

>>> sum(1 for _ in itertools.takewhile(lambda x: x == 0, reversed(l))) 
10 
>>> sum(1 for _ in itertools.dropwhile(lambda x: x == 0, reversed(l))) 
4 

在此,首先是從列表的末尾開始的連續零的數目,而第二從端部開始與所述第一非零,再次剩餘元件的數量。

+0

len(list(itertools.dropwhile(lambda x:x == 0,reversed(l))))? –

+0

itertools.dropwhile完全是我正在尋找的答案。謝謝。 –

+1

@JohnLawrenceAspden請注意,使用'len(list(...))'您首先必須實現整個列表,而'sum'只是通過對每個元素求和'1'來計算長度,而不創建過濾列表。如果清單很大,這可能更可取。 –

1

pop會使你的計算很簡單:

l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,0,0,0,0] 
while not l.pop(): 
    pass 
result = len(l) + 1 
assert result == 4 

編輯

我想使它成爲一個功能,但:

def foo(original): 
    clone = original[:] 
    while not clone.pop(): pass 
    return len(clone) + 1 

l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,0,0,0,0] 
assert foo(l) == 4 

l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0] 
assert foo(l) == 11 
+0

這是一個好主意,但你必須修復你的代碼。 –

+1

你是什麼意思?它適用於我2.7.10和3.6.1的版本 –

+0

這有點貴,因爲你銷燬原始列表*和*必須創建一個新的零列表。 – chepner

1

逆轉列表是一個O(n)的操作,無論如何,所以沒有點。只需走上列表並記下最後一個非零元素的索引。

last = -1 
for i, value in enumerate(l): 
    if value != 0: 
     last = i 

(考慮使用糖耐量試驗,而不是嚴格的平等value。)

散步後,last + 1是第一0中最長的全零後綴列表的索引。那就是,all(x == 0 for x in l[last+1:])將是真實的。

+0

@kindall糟糕。謝謝。 – chepner

+2

'reversed'返回一個生成器,允許您向後遍歷列表,而不是顛倒的新列表。所以不是'O(n)' – acushner

0

這可能是更令人費解比你希望它是,但它的我的2美分反正:

l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0] 

s = len(l) - next(i for i, x in enumerate(l[::-1]) if x != 0) 
print(s) # 11 
3
point = next(index for index, value in enumerate(reversed(l)) if value != 0) 

point = len(l) - point if point else -1 

我們遍歷以相反的順序列表,直到我們得到的第一個非0元素。我們使用該索引並從長度中減去以得到實際的點。

更新了代碼,如評論中的建議。

感謝tobias_k

+0

整潔,但你不必產生整個列表,只需要'next((index of index,value in enumerate(reversed(l))if value!= 0),None) '。另外,檢查應該可能是'!= 0'。 –

+0

謝謝。更新的代碼。不知道下一個。 –

2

有沒有一種特別Pythonic和有效的方式來做到這一點。你可以向後遍歷使用range列表中,但我認爲這是稍微乾淨使用reversed列表迭代器:

def nonzeros(seq): 
    for i, v in enumerate(reversed(seq)): 
     if v: 
      break 
    return len(seq) - i 

lst = [0.01,0.02,0.01,-0.01,0,0,0,0,0,0,0,0,0,0] 
print(nonzeros(lst)) 
lst = [0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0,0] 
print(nonzeros(lst)) 

輸出

4 
11 
1
l = [0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0] 
for i,j in enumerate(reversed(l)) : 
    if j: 
     print (len(l[:-i])) 
     break 

輸出:

11 
+0

使用'顛倒'而不是一個切片。 'l [:: - 1]'會造成整個列表不必要的副本。 – dawg

+0

@dawg,感謝您的建議。已更新 – Transhuman

1

逐字解決方案如何n,例如找到非零元素的最大索引?

res = max(i for i, x in enumerate(lst) if x != 0) + 1 
1

列表的長度與其內部數據一起存儲。從完整列表的長度開始,然後遍歷列表直到找到非零值。

如果列表全部爲零,最壞情況的複雜度應該是O(n)。

在第一個非零值之前的末尾只有幾個零的情況下,它會閃電般快速,例如my_list = [5] * 1000000 + [0, 0]

my_list = [0.01, 0.02, 0.01, -0.01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
n = len(my_list) 
while n: 
    n -= 1 
    if my_list[n] != 0: 
     n += 1 
     break 
>>> n 
4 
1

考慮:

>>> l=[0.01,0.02,0.01,-0.01,0,0,0,0,0,0,1,0,0,0] 

可以前值它在列表中的反向迭代器使用groupby到組的最後一個項目的價值,只要該值是==

>>> last_grp=next((k, len(l)-sum(1 for _ in v)) for k,v in groupby(reversed(l))) 
>>> last_grp 
(0, 11) 

返回的元組的第一個元素將是最後一組的重複值 - 0在這種情況下。那個組的長度是多長。從索引的整個列表長度減去組的開始。

reversed和groupby是迭代器。 next返回迭代器的下一個值。由於這是最後一組,所以只需要一次。這對任何大小的清單都是有效的。

這適用於一組l[x-1]==l[x]k的值設置爲任何值的任何組。 groupby就是這樣做的 - 將相同值的項目組合在一起。

您也可以使用groupby來查找某些條件爲TrueFalse的範圍;在這種情況下,創建比0

di={True:[], False:[]} 
for k, v in groupby(enumerate(l), key=lambda t: t[1]>0): 
    grp=list(v) 
    di[k].append((grp[0][0], grp[-1][0])) 

>>> di 
{False: [(3, 9), (11, 13)], True: [(0, 2), (10, 10)]} 

所以列表l具有在[(0, 2), (10, 10)]每個範圍大於0值和範圍的[(3, 9), (11, 13)]

-1

更新 - 小於或等於0的值>早些時候我誤解了這個問題。 (感謝dawg)

一種方法可以將反轉的列表轉換爲布爾數組並在列表中搜索第一個非零(True)值。 對於這兩種操作(轉換和搜索),我們都可以使用內置函數,因此速度更快,但它以某些內存爲代價(您沒有提及有關內存消耗的任何內容,所以我假設有更多內存可用)。

下面的代碼

bool_list = map(bool, reversed(l)) 
index = bool_list.index(True) 

if index == -1: 
    # No such sub-array found 
    return len(bool_list) 
else: 
    # Start index of the required sub-array 
    return len(bool_list) - index 

在這裏,我們使用逆轉,而不是分割運算[:: - 1]逆轉,因爲它是一臺發電機的功能,並在旅途中返回一個元素,而無需耗費任何額外的內存。我們只需要布爾陣列的內存。

+2

您誤解了OP正在嘗試做什麼。他希望在'0'的最後一次運行l中的索引 - 與列表中的'0'的數目無關。 – dawg

+0

@dawg 我真的很抱歉帶來的不便,我只是誤解了這個問題。 讓我更新答案。謝謝你的通知。 – Divyanshu

0

可以像下面的代碼一樣使用過濾器功能。 nz = len([1 for _ in filter(lambda x: x != 0, l)])