删除与Python列表中的条件匹配的前N个项
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了删除与Python列表中的条件匹配的前N个项相关的知识,希望对你有一定的参考价值。
如果我有一个函数matchCondition(x)
,我如何删除匹配该条件的Python列表中的第一个n
项?
一种解决方案是迭代每个项目,将其标记为删除(例如,通过将其设置为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)
使用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)
然后list(output)
,给你:
[10, 9, 8, 4, 7]
编写一个生成器,它接受可迭代,条件和数量下降。迭代数据并生成不符合条件的项目。如果满足条件,则递增计数器并且不产生该值。一旦计数器达到您想要下降的数量,总是产生物品。
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))
这不需要额外的列表副本,只迭代列表一次,并且只为每个项目调用一次条件。除非你真的想看到整个列表,否则不要在结果上调用list
并直接迭代返回的生成器。
接受的答案对我来说有点太神奇了。这里的流程有望更清晰:
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)))
它类似于davidism回答中的逻辑,但是不是检查每一步的掉落计数,我们只是将循环的其余部分短路。
注意:如果您没有可用的yield from
,只需将其替换为iterator
中剩余项目的其他项目。
如果需要突变:
def do_remove(ls, N, predicate):
i, delete_count, l = 0, 0, len(ls)
while i < l and delete_count < N:
if predicate(ls[i]):
ls.pop(i) # remove item at i
delete_count, l = delete_count + 1, l - 1
else:
i += 1
return ls # for convenience
assert(do_remove(l, N, matchCondition) == [10, 9, 8, 4, 7])
直截了当的Python:
N = 3
data = [1, 10, 2, 9, 3, 8, 4, 7]
def matchCondition(x):
return x < 5
c = 1
l = []
for x in data:
if c > N or not matchCondition(x):
l.append(x)
else:
c += 1
print(l)
如果需要,可以很容易地将其转换为生成器:
def filter_first(n, func, iterable):
c = 1
for x in iterable:
if c > n or not func(x):
yield x
else:
c += 1
print(list(filter_first(N, matchCondition, data)))
使用列表推导:
n = 3
data = [1, 10, 2, 9, 3, 8, 4, 7]
count = 0
def counter(x):
global count
count += 1
return x
def condition(x):
return x < 5
filtered = [counter(x) for x in data if count < n and condition(x)]
由于布尔短路,这也将在找到n个元素后停止检查条件。
启动qazxsw poi,并引入qazxsw poi(qazxsw poi operator),我们可以在列表理解中使用和增加变量:
Python 3.8
这个:
- 将变量assignment expressions (PEP 572)初始化为
:=
,这将表示列表理解中先前匹配的事件的数量 - 如果两者都检查每个项目:
符合排除条件(
# items = [1, 10, 2, 9, 3, 8, 4, 7] total = 0 [x for x in items if not (x < 5 and (total := total + 1) <= 3)] # [10, 9, 8, 4, 7]
) 如果我们还没有丢弃超过我们想要过滤的项目数量: 通过赋值表达式递增total
(0
) 同时将x < 5
的新值与丢弃的最大物品数量进行比较(total
)
以上是关于删除与Python列表中的条件匹配的前N个项的主要内容,如果未能解决你的问题,请参考以下文章