Python的列表理解:如果出现某个值,则修改列表元素

Zoe*_*e L 10 python list-comprehension

如何在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]
Run Code Online (Sandbox Code Playgroud)

基本上在这个例子中,一旦0发生,就将列表的其余部分清零.

Bi *_*ico 8

在某些上下文中,列表理解是许多函数式编程语言中存在的函数mapfilter函数的一种"命令式"语法.你要做的事情通常被称为a accumulate,这是一个稍微不同的操作.除了使用副作用外,您无法实现accumulatea mapfilter.Python允许你在列表理解中有副作用,所以它绝对可能,但是带有副作用的列表推导有点不稳定.以下是使用accumulate实现此方法的方法:

nums = [1,1,0,1,1]

def accumulator(last, cur):
    return 1 if (last == 1 and cur == 1) else 0

list(accumulate(nums, accumulator))
Run Code Online (Sandbox Code Playgroud)

或者在一行中:

list(accumulate(nums, lambda last, cur: 1 if (last == 1 and cur == 1) else 0))
Run Code Online (Sandbox Code Playgroud)

当然,有几种方法可以使用外部状态和带有副作用的列表理解来完成此操作.这是一个例子,它有点冗长,但非常清楚如何操纵状态:

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]
Run Code Online (Sandbox Code Playgroud)


Pru*_*une 6

nums = [1,1,0,1,1]
[int(all(nums[:i+1])) for i in range(len(nums))]
Run Code Online (Sandbox Code Playgroud)

这将逐步完成列表,将all操作符应用于整个子列表.

输出:

[1, 1, 0, 0, 0]
Run Code Online (Sandbox Code Playgroud)

当然,这是O(n ^ 2),但它完成了工作.

更有效的只是找到第一个0的索引.制作一个由许多1s组成的新列表,用适当数量的零填充.

if 0 in nums:
    idx = nums.index(0)
    new_list = [1] * idx + [0] * (len(nums) - idx)
Run Code Online (Sandbox Code Playgroud)

...或者如果原始列表可以包含0和1以外的元素,则复制列表而不是重复1s:

    new_list = nums[:idx] + [0] * (len(nums) - idx)
Run Code Online (Sandbox Code Playgroud)


jim*_*ark 5

我有一个使用列表理解的答案,但@Prune打败了我.这真的只是一个警示性的尾巴,展示了如何在反对这种方法的同时做到这一点.

这是一种可能符合您需求的替代方法:

import itertools
import operator

nums = [1,1,0,1,1]
res = itertools.accumulate(nums, operator.and_)
Run Code Online (Sandbox Code Playgroud)

在这种情况下res是可迭代的.如果你需要一个清单,那么

res = list(itertools.accumulate(nums, operator.and_))
Run Code Online (Sandbox Code Playgroud)

让我们打破这个.该accumulate()函数可用于生成运行总计或"累计总和".如果只传递一个参数,则默认函数为addition.这里我们传入operator.and_.该operator模块导出一组与Python的内部运算符相对应的高效函数.当累计and在0和1的列表上运行时,结果是一个列表,其中1是向上,直到找到第一个0,然后是0之后的所有0.

当然,我们不仅限于使用operator模块中定义的函数.您可以使用任何接受第一个参数中元素类型的2个参数的函数(并且可能返回相同的类型).你可以发挥创意,但在这里我会保持简单并且只是实施and:

import itertools

nums = [1,1,0,1,1]
res = itertools.accumulate(nums, lambda a, b: a and b)
Run Code Online (Sandbox Code Playgroud)

注意:使用operator.and_可能运行得更快.这里我们只是提供一个使用lambda语法的例子.

虽然没有使用列表理解,但对我来说它有类似的感觉.它适合一行,并不难读.