使用元组过滤和拆包处理空情况

6

我有一些并行列表需要根据其中一个列表的值进行筛选。有时我会写下如下代码来对它们进行筛选:

lista = [1, 2, 3]
listb = [7, 8, 9]
filtered_a, filtered_b = zip(*[(a, b) for (a, b) in zip(lista, listb) if a < 3])

这将得到 filtered_a == (1, 2)filtered_b == (7, 8)

然而,将最终条件从 a < 3 改为 a < 0 会导致引发异常:

Traceback (most recent call last):
  ...
ValueError: need more than 0 values to unpack

我知道这是为什么:列表推导式为空,就像调用 zip(* [])一样,这就像 zip(),它只返回一个空列表,无法解包成单独的filtered_a和filtered_b可迭代对象。
有没有更好(更短,更简单,更Pythonic)的过滤函数可以处理空情况?在空情况下,我希望filtered_a和filtered_b是空的可迭代对象,因此任何后续代码都可以保持不变。

1
在这种情况下,您期望filtered_afiltered_b是什么?None?空元组/列表? - Tom Dalton
@TomDalton - 忘记了,谢谢。现在已经添加到问题中了:“在空情况下,我期望filtered_a和filtered_b是空的可迭代对象,这样任何后续代码都可以保持不变。” - Justin
2个回答

4
您可以简单地使用默认值来进行短路处理:
filtered_a, filtered_b = zip(*[(a, b) for a, b in zip(lista, listb) if a < 0]) or ([], [])
print(filtered_b, filtered_a)
# [] []

对于Python 3,您需要在zip返回的迭代器上调用list,以便第一个操作数可以被评估为空列表(而不是迭代器),否则即使迭代器可能为空,也永远不会达到默认值,因为bool(iter([]))True


0

我可能会这样做:

lista = [1, 2, 3]
listb = [7, 8, 9]

filtered_abs = ((a, b) for (a, b) in zip(lista, listb) if a < 3])

for a, b in filtered_abs:
    do_thing(a, b)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接