如何在Python的列表理解中执行以下操作?
nums = [1,1,0,1,1]
oFlag = 1
res = []
for x in nums:
if x == 0:
oFlag = 0
res.append(oFlag)
print(res)
# Output: [1,1,0,0,0]
本质上,在此示例中,一旦发生0
,将列表的其余部分清零。
答案 0 :(得分:8)
在某些情况下,列表推导是许多功能编程语言中存在的map
和filter
函数的一种“命令式”语法。您尝试执行的操作通常称为accumulate
,该操作稍有不同。除了使用副作用之外,不能根据accumulate
和map
来实现filter
。 Python允许您在列表理解中具有副作用,因此这是绝对可能的,但是具有副作用的列表理解却有点奇怪。这是使用累计来实现的方法:
nums = [1,1,0,1,1]
def accumulator(last, cur):
return 1 if (last == 1 and cur == 1) else 0
list(accumulate(nums, accumulator))
或一行:
list(accumulate(nums, lambda last, cur: 1 if (last == 1 and cur == 1) else 0))
当然,有几种方法可以使用外部状态和具有副作用的列表理解功能。这是一个示例,它有点冗长,但是非常明确地说明了状态的操作方式:
class MyState:
def __init__(self, initial_state):
self.state = initial_state
def getNext(self, cur):
self.state = accumulator(self.state, cur)
return self.state
mystate = MyState(1)
[mystate.getNext(x) for x in nums]
答案 1 :(得分:6)
nums = [1,1,0,1,1]
[int(all(nums[:i+1])) for i in range(len(nums))]
这会逐步遍历列表,直到此时将all
运算符应用于整个子列表。
输出:
[1, 1, 0, 0, 0]
可以,这是 O(n ^ 2),但是可以完成工作。
更有效的方法是简单地找到前0个索引。
新建一个包含这么多1
的列表,并填充适当数量的零。
if 0 in nums:
idx = nums.index(0)
new_list = [1] * idx + [0] * (len(nums) - idx)
...,或者如果原始列表可以包含0和1以外的元素,请将列表复制到尽可能远的位置,而不要重复1
:
new_list = nums[:idx] + [0] * (len(nums) - idx)
答案 2 :(得分:5)
我有一个使用列表理解的答案,但是@Prune击败了我。这实际上只是一条警告尾巴,显示了反对该方法的论点时该如何做。
这是一种可能满足您需求的替代方法:
import itertools
import operator
nums = [1,1,0,1,1]
res = itertools.accumulate(nums, operator.and_)
在这种情况下,res
是可迭代的。如果您需要列表,那么
res = list(itertools.accumulate(nums, operator.and_))
让我们分解一下。 accumulate()
函数可用于生成运行总计或“累计总和”。如果仅传递一个参数,则默认功能为加法。在这里,我们传入operator.and_。 operator
模块导出一组与Python的内在运算符相对应的有效函数。当累积的and
在0和1的列表上运行时,结果是列表中的1一直到找到第一个0,然后是所有0。
当然,我们不仅限于使用operator
模块中定义的函数。您可以使用任何在第一个参数中接受两个元素类型的参数的函数(并且可能返回相同的类型)。您可以发挥创造力,但在这里我将使其保持简单,仅实现and
:
import itertools
nums = [1,1,0,1,1]
res = itertools.accumulate(nums, lambda a, b: a and b)
注意:使用operator.and_可能运行得更快。在这里,我们只是提供一个使用lambda语法的示例。
虽然没有使用列表理解,但对我来说却有类似的感觉。它合而为一,读起来也不难。
答案 3 :(得分:3)
对于列表理解方法,可以将index
与enumerate
结合使用:
firstIndex = nums.index(0) if 0 in nums else -1
[1 if i < firstIndex else 0 for i, x in enumerate(nums)]
使用numpy
的另一种方法:
import numpy as np
print(np.cumprod(np.array(nums) != 0).tolist())
#[1, 1, 0, 0, 0]
在这里,我们将转换nums
转换为一个numpy数组,并检查值是否不等于0。然后取该数组的累加乘积,知道一旦找到0,我们将乘以从那以后向前减0。
答案 4 :(得分:1)
这是一个线性时间解决方案,它不改变全局状态,不需要nums
以外的任何其他迭代器,并且可以满足您的要求,尽管需要一些辅助数据结构并使用严重黑名单的理解力:
>>> nums = [1,1,0,1,1]
>>> [f for f, ns in [(1, nums)] for n in ns for f in [f & (n==1)]]
[1, 1, 0, 0, 0]
请勿使用。使用原始的for循环。它更具可读性,并且几乎可以肯定更快。不要努力将所有内容放在列表理解中。力求使您的代码简单,易读和可维护,而您的代码已经是,而上面的代码则不是。