Python:掩盖列表的优雅而有效的方法

Dev*_*per 16 python arrays list masking

例:

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  
Run Code Online (Sandbox Code Playgroud)

结果是:

>>> 
[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]
Run Code Online (Sandbox Code Playgroud)

如您所见,与列表相比,数组上的屏蔽操作更加优雅.如果您尝试在列表上使用数组屏蔽方案,您将收到错误:

>>> 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
Run Code Online (Sandbox Code Playgroud)

问题是为lists 寻找优雅的掩饰.

更新:
答案jamylak被接受引入,compress但是提到的要点Joel Cornett使解决方案完成了我感兴趣的所需形式.

>>> mlist = MaskableList
>>> mlist(lst)[msk]
>>> [4, 5, 6]
Run Code Online (Sandbox Code Playgroud)

jam*_*lak 26

你在找 itertools.compress

来自文档的示例

相当于:

def compress(data, selectors):
    # compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
    return (d for d, s in izip(data, selectors) if s)
Run Code Online (Sandbox Code Playgroud)

  • 到目前为止最好的解决方案在这里 (2认同)

Joe*_*ett 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))
Run Code Online (Sandbox Code Playgroud)

用法:

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

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

from itertools import izip_longest

[i[0] for i in izip_longest(myList, mask[:len(myList)], fillvalue=True) if i[1]]
Run Code Online (Sandbox Code Playgroud)


bie*_*ltb 6

如果使用的是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]
Run Code Online (Sandbox Code Playgroud)