2017-08-09 70 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)])