根据来自另一个列表的 True/False 从列表中过滤元素

Filter elements from list based on True/False from another list

在 vanilla Python 3 中是否有一种惯用的方法来屏蔽数组的元素?例如:

a = [True, False, True, False]
b = [2, 3, 5, 7]
b[a]

我希望 b[a] 会 return [2, 5],但我得到一个错误:

TypeError: list indices must be integers or slices, not list

在 R 中,这按我预期的方式工作(使用 c() 而不是 [] 来创建列表)。我知道 NumPy 有 MaskedArray 可以做到这一点,我正在寻找一种惯用的方法来在普通香草 Python 中做到这一点。当然,我可以使用循环并遍历掩码列表和元素列表,但我希望有一种更有效的方法来使用更高级别的抽象来掩码元素。

我认为没有很多方法可以做到这一点,您可以使用 zip:

print([y for x, y in zip(a, b) if x])

输出:

[2, 5]

您还可以为此创建一个 class__getitem__

class index:
    def __init__(self, seq):
        self.seq = seq
    def __getitem__(self, boolseq):
        return [x for x, y in zip(boolseq, self.seq) if y]
print(index(a)[b])

输出:

[2, 5]

您可以使用 itertools.compress:

>>> from itertools import compress
>>> a = [True, False, True, False]
>>> b = [2, 3, 5, 7]


>>> list(compress(b, a))
[2, 5]

参考"itertools.compress()" document了解更多详情

您可以使用列表理解:

[b[i] for i in range(len(a)) if a[i]]

[b[i] for i,mask in enumerate(a) if maks]

在这两种情况下,列表都是通过遍历每个元素创建的,并且仅在掩码为 true 时插入它。

在众多选项中,您可以:

1。使用 itertools compress

from itertools import compress
a = [True, False, True, False]
b = [2, 3, 5, 7]

result_itertools = list(compress(b, a))
print(result_itertools)

2。使用 Filter Function

result_filter = list(filter(lambda x: x[0], zip(a, b)))
for item in result_filter:
    print(item[1])
# 2
# 5

3。使用 List Comprehension

result_comprehension = [value for bool_, value in zip(a, b) if bool_]
print(result_comprehension)
# [2, 5]

您可以使用 pandas.Series,它允许像数据框一样使用布尔数组过滤数据

from pandas import Series

a = [True, False, True, False]
b = [2, 3, 5, 7]

res = Series(b)[a].tolist()

print(res)  # [2, 5]