我想在Python中获取一个数字列表,并用之前的非零值替换所有零,例如[1, 0, 0, 2, 0]
应该[1,1,1,2,2]
。我知道列表中的第一个条目是非零的,因此初始化应该不是问题。我可以在一个循环中完成它但是有更多的pythonic方式吗?
澄清:这应该适用于任何数字列表,例如: [100.7, 0, -2.34]
应该成为[100.7, 100.7, -2.34]
。
答案 0 :(得分:3)
这可以在很短的循环中完成:
a = [1, 0, 0, 2, 0]
b = []
for i in a:
b.append(i if i else b[-1])
print b
# [1, 1, 1, 2, 2]
仅当存在先前的非零值时才起作用(即,如果以0开头则失败)。
由于无法从内部引用列表理解,因此无法将列表推广为
答案 1 :(得分:2)
您可以利用可变的默认参数来避免全局或静态变量存储最后一个非零元素:
def val(x,z=[0]):
if x:
z[0] = x
return z[0]
[val(x) for x in a]
将按预期产生[1, 1, 1, 2, 2]
答案 2 :(得分:1)
在3.3中,有一个单行使用accumulate
:
>>> from itertools import accumulate
>>> seq = [1, 0, 0, 2, 0]
>>> list(accumulate(seq, lambda x,y: y if y else x))
[1, 1, 1, 2, 2]
>>> seq = [100.7, 0, -2.34]
>>> list(accumulate(seq, lambda x,y: y if y else x))
[100.7, 100.7, -2.34]
(我猜也可以使用or
,但我发现三元更容易阅读。)
答案 3 :(得分:0)
这不建议用于简单,可读的循环。但...
>>> my_list = [1, 0, 0, 2, 0]
>>> def set_sentinel(x):
... global sentinel
... sentinel = x
... return False
...
>>> [set_sentinel(elem) or elem if elem else sentinel for elem in my_list]
[1, 1, 1, 2, 2]
答案 4 :(得分:0)
好吧,如果您明确要避免for
循环,那么这是一个单行。但这不如循环效率高。
>>> l = [1, 0, 0, 2, 0]
>>> [l[i] if l[i] else filter(lambda x: x > 0, l[:i])[-1] for i in range(len(l))]
[1, 1, 1, 2, 2]
对于每个零的元素,您将找到该元素之前的所有非零元素,并获取最后一个元素。
答案 5 :(得分:0)
冒着听起来陈腐的风险..不。使用循环。我认为这是表达你想要的最清晰的方式。
for i in range(1, len(a)):
if a[i] == 0:
a[i] = a[i-1]
我见过许多以“Pythonic”为名的暴行。根据最能表达您意图的内容仔细选择。不要试图盲目地优化最少的代码行或最巧妙的实现。