2010-07-05 16 views
47

Mam kilka list posiadające wszystkie taką samą liczbę wpisów (każdy określające właściwość Object):Python: Wybierz podzbiór z listy na podstawie indeksu ustawić

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

i listy z flagami tej samej długości

good_objects = [True, False, False, True] 

(co może być łatwo podstawiona przez równoważną liście indeksów:

good_indices = [0, 3] 

co jest najprostszym wag ay do generowania nowych list property_asel, property_bsel, ... które zawierają tylko wartości wskazane przez wpisy lub indeksy?

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

Odpowiedz

64

może po prostu użyć list comprehension:

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

lub

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

Ten ostatni jest szybszy, ponieważ istnieje mniej good_indices niż długość property_a, zakładając good_indices są precomputed zamiast generowane w locie.


Edycja: Opcja pierwsza odpowiada itertools.compress dostępny od Pythonie 2.7/3.1. Zobacz odpowiedź: @Gary Kerr.

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

Czy użycie "zip" tutaj wprowadza karę za wydajność? – fuenfundachtzig

+1

@fuen: Tak. Powoduje wiele na Pythonie 2 (zamiast tego użyj [itertools.izip] (http://docs.python.org/library/itertools.html#itertools.izip), nie tyle na Pythonie 3. Jest tak dlatego, że 'zip 'w Pythonie 2 utworzy nową listę, ale w Pythonie 3 po prostu zwróci (leniwy) generator. – kennytm

+0

OK, więc powinienem trzymać się twojej drugiej propozycji, ponieważ to stanowi centralną część mojego kodu. – fuenfundachtzig

17

Widzę 2 opcje.

  1. Korzystanie 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. Korzystanie z listy ze zrozumieniem i zip go:

    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] 
    
+0

Użyj 8 spacji, aby sformatować kod na liście. – kennytm

+1

Korzystanie z Numpy jest dobrą sugestią, ponieważ OP wydaje się chcieć przechowywać numery na listach. Tablica dwuwymiarowa byłaby jeszcze lepsza. – Philipp

+0

Jest to również dobra sugestia, ponieważ będzie to bardzo znana składnia dla użytkowników R, gdzie ten rodzaj selekcji jest bardzo silny, szczególnie gdy jest zagnieżdżony i/lub wielowymiarowy. –

13

korzystać z wbudowanych funkcji zip

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

EDIT

Po prostu patrząc na nowych funkcji 2.7. W module itertools jest teraz funkcja podobna do powyższego kodu.

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

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

Jestem rozczarowany przez użycie' itertools.compress' tutaj.Zrozumienie listy jest * znacznie * bardziej czytelne, bez konieczności wykopywania tego, co robi kompilator. – PaulMcG

+4

Hm, znajduję kod przy użyciu kompresji znacznie bardziej czytelny :) Może jestem stronniczy, ponieważ robi dokładnie to, co chcę. – fuenfundachtzig

3

Zakładając masz tylko listę elementów i listę prawdziwych/wymaganych wskaźników, powinno to być najszybszy:

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

Oznacza to wybór nieruchomości będzie nie tylko tyle rund, ile jest prawdziwych/wymaganych wskaźników.Jeśli masz dużo wykazów nieruchomości, które następują z zasadami pojedynczych znaczników (prawda/fałsz) listę można utworzyć listę indeksów przy użyciu tych samych zasad lista ze zrozumieniem:

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

This iteracji każdej pozycji good_objects (podczas zapamiętywania indeksu z wyliczeniem) i zwraca tylko indeksy, w których pozycja jest prawdziwa.


Dla nikogo nie otrzymuję listy ze zrozumieniem, tutaj jest wersja proza ​​angielski z kodem pogrubione:

lista indeks dla każda grupa indeksu, poz że istnieje wwyliczenie z dobrych obiektów, jeśli (gdzie) pozycja True

1

Języki Matlab i Scilab oferują prostszą i bardziej elegancką składnię niż w pythonie na pytanie, które zadajesz, więc myślę, że najlepiej jest naśladować Matlab/Scilab przy użyciu pakietu Numpy w Pythonie. W ten sposób rozwiązanie problemu jest bardzo zwięzły i elegancki:

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 próbuje naśladować Matlab/Scilab ale chodzi w cenie: trzeba zadeklarować każdej listy ze słowem kluczowym „tablicy”, coś, co przeładuje twój skrypt (ten problem nie istnieje w Matlab/Scilab). Zauważ, że to rozwiązanie jest ograniczone do tablic liczb, co ma miejsce w twoim przykładzie.

+1

Nigdzie w pytaniu nie wspomina NumPy - nie ma potrzeby wyrażania swojej opinii na temat NumPy vs Matlab. Listy Pythona to ** nie ** to samo, co tablice NumPy, nawet jeśli oba w przybliżeniu odpowiadają wektorom. (Listy Pythona przypominają tablice macierzy Matlab - każdy element może mieć inny typ danych, tablice NumPy są bardziej ograniczone, aby umożliwić pewne optymalizacje). Możesz uzyskać podobną składnię do swojego przykładu poprzez wbudowany w Python 'filter' lub bibliotekę zewnętrzną' pandas'. Jeśli zamierzasz zamieniać języki, możesz również wypróbować R, ale * nie o to pyta *. – Livius

Powiązane problemy