Exemple:
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
et les résultats sont:
>>>
[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]
Comme vous le voyez, l'opération de masquage sur le tableau est plus élégante que la liste. Si vous essayez d'utiliser le schéma de masquage de tableau dans la liste, vous obtiendrez une erreur:
>>> 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
La question est de trouver un masquage élégant pour list
s.
Mises à jour:
La réponse de jamylak
a été acceptée pour introduire compress
mais les points mentionnés par Joel Cornett
a rendu la solution complète à la forme souhaitée de mon intérêt.
>>> mlist = MaskableList
>>> mlist(lst)[msk]
>>> [4, 5, 6]
Tu recherches itertools.compress
Exemple tiré de la documentation
Équivalent à:
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)
Étant donné que jamylak a déjà répondu à la question par une réponse pratique, voici mon exemple de liste avec prise en charge du masquage intégrée (totalement inutile, au fait):
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))
Usage:
>>> myList = MaskableList(range(10))
>>> myList
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> mask = [0, 1, 1, 0]
>>> myList[mask]
[1, 2]
Notez que compress
s'arrête lorsque les données ou le masque s'épuisent. Si vous souhaitez conserver la partie de la liste qui s'étend au-delà de la longueur du masque, vous pouvez essayer quelque chose comme:
from itertools import izip_longest
[i[0] for i in izip_longest(myList, mask[:len(myList)], fillvalue=True) if i[1]]
Si vous utilisez Numpy, vous pouvez le faire facilement en utilisant le tableau Numpy sans installer aucune autre bibliothèque:
>> 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]
je ne le trouve pas élégant. Il est compact, mais a tendance à prêter à confusion, car la construction est très différente de la plupart des langues.
Comme Rossum l'a dit à propos de la conception du langage, nous passons plus de temps à le lire qu'à l'écrire. Plus la construction d'une ligne de code est obscure, plus elle devient confuse pour les autres, qui peuvent manquer de familiarité avec Python, même s'ils ont une compétence complète dans un certain nombre d'autres langues.
La lisibilité l'emporte sur les notations courtes tous les jours dans le monde réel du code de maintenance. Tout comme réparer votre voiture. De gros dessins avec beaucoup d'informations facilitent le dépannage.
Pour moi, je préfère de loin dépanner le code de quelqu'un qui utilise le formulaire long
print [lst[i] for i in xrange(len(lst)) if msk[i]]
que le masque de notation courte numpy. Je n'ai pas besoin d'avoir une connaissance particulière d'un package Python spécifique pour l'interpréter).