Python: Sélectionnez le sous-ensemble de la liste en fonction du jeu d’index

J’ai plusieurs listes ayant le même nombre d’entrées (chacune spécifiant une propriété d’object):

property_a = [545., 656., 5.4, 33.] property_b = [ 1.2, 1.3, 2.3, 0.3] ... 

et liste avec des drapeaux de même longueur

 good_objects = [True, False, False, True] 

(qui pourrait facilement être remplacé par une liste d’index équivalente:

 good_indices = [0, 3] 

Quel est le moyen le plus simple de générer de nouvelles listes property_asel , property_bsel , … qui ne contiennent que les valeurs indiquées par les entrées True ou les index?

 property_asel = [545., 33.] property_bsel = [ 1.2, 0.3] 

Vous pouvez simplement utiliser la compréhension de liste :

 property_asel = [val for is_good, val in zip(good_objects, property_a) if is_good] 

ou

 property_asel = [property_a[i] for i in good_indices] 

Le dernier est plus rapide car il y a moins de good_indices que la longueur de property_a , en supposant que good_indices soit précalculé au lieu d’être généré à la volée.


Edit : La première option est équivalente à itertools.compress disponible depuis Python 2.7 / 3.1. Voir la réponse de @Gary Kerr .

 property_asel = list(itertools.compress(good_objects, property_a)) 

Je vois 2 options.

  1. En utilisant numpy:

     property_a = numpy.array([545., 656., 5.4, 33.]) property_b = numpy.array([ 1.2, 1.3, 2.3, 0.3]) good_objects = [True, False, False, True] good_indices = [0, 3] property_asel = property_a[good_objects] property_bsel = property_b[good_indices] 
  2. En utilisant une liste de compréhension et le compresser:

     property_a = [545., 656., 5.4, 33.] property_b = [ 1.2, 1.3, 2.3, 0.3] good_objects = [True, False, False, True] good_indices = [0, 3] property_asel = [x for x, y in zip(property_a, good_objects) if y] property_bsel = [property_b[i] for i in good_indices] 

Utilisez la fonction zip intégrée

 property_asel = [a for (a, truth) in zip(property_a, good_objects) if truth] 

MODIFIER

Il suffit de regarder les nouvelles fonctionnalités de 2.7. Il y a maintenant une fonction dans le module itertools qui est similaire au code ci-dessus.

http://docs.python.org/library/itertools.html#itertools.compress

 itertools.compress('ABCDEF', [1,0,1,0,1,1]) => A, C, E, F 

En supposant que vous ayez uniquement la liste des éléments et une liste des indices vrais / requirejs, cela devrait être le plus rapide:

 property_asel = [ property_a[index] for index in good_indices ] 

Cela signifie que la sélection de propriétés ne fera que autant de tours qu’il y a d’indices vrais / requirejs. Si vous avez beaucoup de listes de propriétés qui suivent les règles d’une liste de tags (true / false), vous pouvez créer une liste d’indices en utilisant les mêmes principes de compréhension de liste:

 good_indices = [ index for index, item in enumerate(good_objects) if item ] 

Cela parcourt chaque élément de good_objects (tout en gardant en mémoire son index avec enumerate) et ne renvoie que les index où l’élément est true.


Pour ceux qui ne comprennent pas la liste, voici une version en prose anglaise avec le code en gras:

liste l’ index pour chaque groupe d’ index, élément existant dans une énumération de bons objects , si (où) l’ élément est True

Les langages Matlab et Scilab offrent une syntaxe plus simple et plus élégante que Python pour la question que vous posez. Je pense donc que le mieux que vous puissiez faire est d’imiter Matlab / Scilab en utilisant le package Numpy en Python. En faisant cela, la solution à votre problème est très concise et élégante:

 from numpy import * property_a = array([545., 656., 5.4, 33.]) property_b = array([ 1.2, 1.3, 2.3, 0.3]) good_objects = [True, False, False, True] good_indices = [0, 3] property_asel = property_a[good_objects] property_bsel = property_b[good_indices] 

Numpy essaie d’imiter Matlab / Scilab mais cela a un coût: vous devez déclarer chaque liste avec le mot-clé “array”, ce qui surchargera votre script (ce problème n’existe pas avec Matlab / Scilab). Notez que cette solution est limitée aux tableaux de nombre, ce qui est le cas dans votre exemple.