删除与Python列表中的条件匹配的前N个项

Tho*_*son 59 python list-comprehension list

如果我有一个函数matchCondition(x),如何删除n匹配该条件的Python列表中的第一项?

一种解决方案是迭代每个项目,将其标记为删除(例如,通过将其设置为None),然后用理解来过滤列表.这需要对列表进行两次迭代并改变数据.是否有更惯用或更有效的方法来做到这一点?

n = 3

def condition(x):
    return x < 5

data = [1, 10, 2, 9, 3, 8, 4, 7]
out = do_remove(data, n, condition)
print(out)  # [10, 9, 8, 4, 7] (1, 2, and 3 are removed, 4 remains)
Run Code Online (Sandbox Code Playgroud)

Jon*_*nts 63

使用itertools.filterfalse和的一种方式itertools.count:

from itertools import count, filterfalse

data = [1, 10, 2, 9, 3, 8, 4, 7]
output = filterfalse(lambda L, c=count(): L < 5 and next(c) < 3, data)
Run Code Online (Sandbox Code Playgroud)

然后list(output),给你:

[10, 9, 8, 4, 7]
Run Code Online (Sandbox Code Playgroud)

  • @wcarroll for python 2.x它是`ifilterfalse` (6认同)
  • 我从来没有听说过`filterfalse` - 为什么要使用它而不是带有否定条件的内置`filter`(在这种情况下,`L> = 5或next(c)> = 3`)?"filterfalse"的存在是否打破了Python的黄金法则,"只有一种正确的方法可以做任何事情"? (4认同)
  • 如果我们不必在超过最大跌落计数时每次都检查[first]条件,那将是很好的. (2认同)

dav*_*ism 29

编写一个生成器,它接受可迭代,条件和数量下降.迭代数据并生成不符合条件的项目.如果满足条件,则递增计数器并且不产生该值.一旦计数器达到您想要下降的数量,总是产生物品.

def iter_drop_n(data, condition, drop):
    dropped = 0

    for item in data:
        if dropped >= drop:
            yield item
            continue

        if condition(item):
            dropped += 1
            continue

        yield item

data = [1, 10, 2, 9, 3, 8, 4, 7]
out = list(iter_drop_n(data, lambda x: x < 5, 3))
Run Code Online (Sandbox Code Playgroud)

这不需要额外的列表副本,只迭代列表一次,并且只为每个项目调用一次条件.除非您确实想要查看整个列表,否则不要list对结果进行调用并直接迭代返回的生成器.


wim*_*wim 24

接受的答案对我来说有点太神奇了.这里的流程有望更清晰:

def matchCondition(x):
    return x < 5


def my_gen(L, drop_condition, max_drops=3):
    count = 0
    iterator = iter(L)
    for element in iterator:
        if drop_condition(element):
            count += 1
            if count >= max_drops:
                break
        else:
            yield element
    yield from iterator


example = [1, 10, 2, 9, 3, 8, 4, 7]

print(list(my_gen(example, drop_condition=matchCondition)))
Run Code Online (Sandbox Code Playgroud)

它类似于大卫答案中的逻辑,但是不是检查每一步的丢弃计数,我们只是将循环的其余部分短路.

注意:如果您没有yield from可用的,只需将其替换为另一个用于循环其余项目iterator.