126 Stimmen

Python: Wählen Sie eine Teilmenge aus der Liste basierend auf dem Index-Set aus

Ich habe mehrere Listen, die alle die gleiche Anzahl von Einträgen haben (jeder definiert eine Objekteigenschaft):

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

und eine Liste mit Flaggen der gleichen Länge

good_objects = [True, False, False, True]

(die leicht durch eine äquivalente Indexliste ersetzt werden könnte:

good_indices = [0, 3]

Wie lässt sich am einfachsten neue Listen property_asel, property_bsel, ... generieren, die nur die Werte enthalten, die entweder durch die True-Einträge oder die Indizes angegeben sind?

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

166voto

kennytm Punkte 488916

Sie könnten einfach Listenabstraktion verwenden:

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

oder

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

Letzteres ist schneller, da es weniger good_indices gibt als die Länge von property_a, vorausgesetzt, dass good_indices vorab berechnet werden, anstatt sie dynamisch zu generieren.


Bearbeiten: Die erste Option ist äquivalent zu itertools.compress, verfügbar seit Python 2.7/3.1. Siehe Antwort von @Gary Kerr.

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

33voto

Wolph Punkte 73880

Ich sehe 2 Optionen.

  1. Mit numpy verwenden:

    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. Mit einer List Comprehension und zip it verwenden:

    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]

18voto

Gary Kerr Punkte 12468

Verwenden Sie die integrierte Funktion zip

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

EDIT

Nur einen Blick auf die neuen Funktionen von 2.7 werfen. Es gibt jetzt eine Funktion im itertools-Modul, die ähnlich dem obigen Code ist.

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

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

10voto

Eyrofire Punkte 300

Angenommen, Sie haben nur die Liste der Elemente und eine Liste der wahren/erforderlichen Indizes, sollte dies am schnellsten sein:

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

Dies bedeutet, dass die Eigenschaftenauswahl nur so viele Runden macht, wie es wahre/erforderliche Indices gibt. Wenn Sie viele Eigenschaftslisten haben, die den Regeln einer einzelnen Tags (wahr/falsch) Liste folgen, können Sie eine Indizes-Liste erstellen, die die gleichen Prinzipien der Listenkomprehension verwendet:

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

Dies geht jedes Element in good_objects durch (indem es sich mit enumerate an seinen Index erinnert) und gibt nur die Indizes zurück, an denen das Element wahr ist.


Für alle, die die Listenkomprehension nicht verstehen, hier ist eine englische Prosa-Version mit dem Code, der fett hervorgehoben ist:

Listen Sie den Index für jede Gruppe von Index, Element auf, die in einer Aufzählung von guten Objekten existiert, wenn (wo) das Element wahr ist

-1voto

FredAndre Punkte 17

Die Sprachen Matlab und Scilab bieten eine einfachere und elegantere Syntax als Python für die Frage, die Sie stellen, daher denke ich, dass das Beste, was Sie tun können, ist, Matlab/Scilab zu imitieren, indem Sie das Numpy-Paket in Python verwenden. Dadurch ist die Lösung für Ihr Problem sehr prägnant und elegant:

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 versucht, Matlab/Scilab zu imitieren, aber das hat seinen Preis: Sie müssen jede Liste mit dem Stichwort "array" deklarieren, was Ihr Skript überlasten wird (dieses Problem besteht nicht bei Matlab/Scilab). Beachten Sie, dass diese Lösung auf Arrays von Zahlen beschränkt ist, was in Ihrem Beispiel der Fall ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X