web-dev-qa-db-ja.com

Python:リストをマスクするエレガントで効率的な方法

例:

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]

ご覧のとおり、配列のマスキング操作はリストよりもエレガントです。リストの配列マスキングスキームを使用しようとすると、エラーが発生します。

>>> 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]
19
Developer

あなたは探している - 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)
26
jamylak

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]]
7
Joel Cornett

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]
5
biendltb

エレガントだとは思いません。コンパクトですが、構成がほとんどの言語とは非常に異なるため、混乱する傾向があります。

Rossumが言語設計について述べたように、私たちはそれを書くよりも読むことに多くの時間を費やしています。コード行の構成が不明瞭であるほど、他の多くの言語で完全な能力を持っているにもかかわらず、Pythonに精通していない他の人にとって、コードはさらに混乱します。

読みやすさは、コードを処理する現実の世界では、毎日、短い形式の表記よりも優先されます。車を修理するのと同じです。大量の情報を含む大きな図面により、トラブルシューティングが非常に簡単になります。

私にとっては、長い形式を使用する誰かのコードをかなりトラブルシューティングしたい

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

派手な短い表記マスクよりも。特定のPythonパッケージを解釈するための特別な知識は必要ありません。

3
Jim