29

例子:

from __future__ import division
import numpy as np

n = 8
"""masking lists"""
lst = range(n)
print lst

# the mask (filter)
msk = [(el>3) and (el<=6) for el in lst]
print msk

# use of the mask
print [lst[i] for i in xrange(len(lst)) if msk[i]]

"""masking arrays"""
ary = np.arange(n)
print ary

# the mask (filter)
msk = (ary>3)&(ary<=6)
print msk

# use of the mask
print ary[msk]                          # very elegant  

结果是:

>>> 
[0, 1, 2, 3, 4, 5, 6, 7]
[False, False, False, False, True, True, True, False]
[4, 5, 6]
[0 1 2 3 4 5 6 7]
[False False False False  True  True  True False]
[4 5 6]

如您所见,与列表相比,对数组进行屏蔽的操作更加优雅。如果你尝试使用 list 上的数组掩码方案,你会得到一个错误:

>>> lst[msk]
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
TypeError: only integer arrays with one element can be converted to an index

问题是为lists 找到一个优雅的掩码。

更新:
的答案jamylak被接受为介绍compress但是提到的点Joel Cornett使解决方案完全符合我感兴趣的所需形式。

>>> mlist = MaskableList
>>> mlist(lst)[msk]
>>> [4, 5, 6]
4

6 回答 6

46

如果您正在使用numpy

>>> import numpy as np
>>> a = np.arange(8)
>>> mask = np.array([False, False, False, False, True, True, True, False], dtype=np.bool)
>>> a[mask]
array([4, 5, 6])

如果你不使用你正在寻找的 numpyitertools.compress

>>> from itertools import compress
>>> a = range(8)
>>> mask = [False, False, False, False, True, True, True, False]
>>> list(compress(a, mask))
[4, 5, 6]
于 2012-04-23T04:28:51.850 回答
16

如果您使用的是 Numpy,您可以使用 Numpy 数组轻松完成,而无需安装任何其他库:

>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>> msk = [ True, False, False,  True,  True,  True,  True, False, False, False]
>> a = np.array(a) # convert list to numpy array
>> result = a[msk] # mask a
>> result.tolist()
[0, 3, 4, 5, 6]
于 2018-08-13T16:02:22.763 回答
7

由于 jamylak 已经用一个实用的答案回答了这个问题,这里是我的一个带有内置屏蔽支持的列表示例(完全没有必要,顺便说一句):

from itertools import compress
class MaskableList(list):
    def __getitem__(self, index):
        try: return super(MaskableList, self).__getitem__(index)
        except TypeError: return MaskableList(compress(self, index))

用法:

>>> myList = MaskableList(range(10))
>>> myList
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> mask = [0, 1, 1, 0]
>>> myList[mask]
[1, 2]

请注意,compress当数据或掩码用完时停止。如果您希望保留超出掩码长度的列表部分,您可以尝试以下操作:

from itertools import izip_longest

[i[0] for i in izip_longest(myList, mask[:len(myList)], fillvalue=True) if i[1]]
于 2012-04-23T04:54:45.110 回答
4

我不认为它优雅。它很紧凑,但往往令人困惑,因为它的结构与大多数语言非常不同。

正如罗森所说的语言设计,我们花更多的时间阅读它而不是写它。一行代码的构造越模糊,对其他人来说就越容易混淆,他们可能对 Python 不熟悉,尽管他们对任何数量的其他语言都有完全的能力。

在服务代码的现实世界中,可读性每天都胜过短格式符号。就像修车一样。包含大量信息的大型图纸使故障排除变得更加容易。

对我来说,我更愿意对使用长格式的某人的代码进行故障排除

print [lst[i] for i in xrange(len(lst)) if msk[i]]

比 numpy 短符号掩码。我不需要对特定的 Python 包有任何特殊的知识来解释它。

于 2015-12-03T23:57:15.297 回答
1

以下在 Python 3 中运行良好:

np.array(lst)[msk]

如果您需要返回列表作为结果:

np.array(lst)[msk].tolist()
于 2021-01-21T22:11:59.457 回答
0

你也可以只使用 list 和 zip

  1. 定义一个函数
def masklist(mylist,mymask):
    return [a for a,b in zip(mylist,mymask) if b]
  1. 用它!
n = 8
lst = range(n)
msk = [(el>3) and (el<=6) for el in lst]
lst_msk = masklist(lst,msk)
print(lst_msk)
于 2020-05-27T13:09:03.690 回答