2013-05-22 19 views
23

Mam długą listę liczb zmiennoprzecinkowych od 1 do 5, nazywaną "średnią" i chcę zwrócić listę indeksów dla elementów, które są mniejsze niż lub większe niż bWyszukiwanie indeksów pasujących elementów na liście w Pythonie

def find(lst,a,b): 
    result = [] 
    for x in lst: 
     if x<a or x>b: 
      i = lst.index(x) 
      result.append(i) 
    return result 

matches = find(average,2,4) 

Jednak, co zaskakujące, wyniki dla "dopasowań" mają w nim wiele powtórzeń, np. [2, 2, 10, 2, 2, 2, 19, 2, 10, 2, 2, 42, 2, 2, 10, 2, 2, 2, 10, 2, 2, ...].

Dlaczego tak się dzieje?

+0

Możliwy duplikat [Jak znaleźć wszystkie wystąpienia elementu na liście?] (Https://stackoverflow.com/questions/6294179/how-to-find-all-occurrences-of-an-element-in -a-list) – Qiu

Odpowiedz

52

Używasz .index(), który znajdzie tylko pierwsze wystąpienie Twojej wartości na liście. Więc jeśli masz wartość 1,0 na indeksie 2 i na indeksie 9, to .index(1.0) będzie zawsze wracać 2, bez względu na to, ile razy pojawi się 1.0 na liście.

Zastosowanie enumerate() dodać indeksy do pętli Zamiast:

def find(lst, a, b): 
    result = [] 
    for i, x in enumerate(lst): 
     if x<a or x>b: 
      result.append(i) 
    return result 

można zwinąć ten w listowego:

def find(lst, a, b): 
    return [i for i, x in enumerate(lst) if x<a or x>b] 
+0

Teraz całkowicie to rozumiem. Zrozumienie listy jest naprawdę dobre, wciąż staram się przystosować do tego rodzaju kompaktowej formy w Pythonie. Twoja odpowiedź jest doskonała, dziękuję bardzo! –

+0

Co zabawne jest to, że zły wynik z powtórzeniami wydaje się działać dobrze dla mojego późniejszego wykorzystania, ponieważ chcę go użyć do wyodrębnienia kolumn dużej matrycy. Wygląda na to, że powtórzenia nie mają wpływu na cięcie. –

+1

Ciągle otrzymasz prawidłowe wartości z listy, te same wartości znajdują się w indeksie 2 i niezależnie od późniejszych indeksów. Ale jest to błąd, który czeka, aby się wydarzyć, gryząc cię w innym punkcie kodu. –

-1
>>> average = [1,3,2,1,1,0,24,23,7,2,727,2,7,68,7,83,2] 
>>> matches = [i for i in range(0,len(average)) if average[i]<2 or average[i]>4] 
>>> matches 
[0, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15] 
+0

To wcale nie jest to, czego chciał OP. – TerryA

+0

ponownie przeczytać pytanie: p – TerryA

+0

Nadal, 'wyliczenie' jest tu wyraźnym zwycięzcą :) – root

2

Jest to dość ciężki zależność, ale jeśli” Robisz dużo tego rodzaju rzeczy, które powinieneś rozważyć używając numpy.

In [56]: import random, numpy 

In [57]: lst = numpy.array([random.uniform(0, 5) for _ in xrange(1000)]) # example list 

In [58]: a, b = 1, 3 

In [59]: numpy.flatnonzero((lst > a) & (lst < b))[:10] 
Out[59]: array([ 0, 12, 13, 15, 18, 19, 23, 24, 26, 29]) 

W odpowiedzi na pytanie Seanny123 za użyłem ten kod czasowy:

import numpy, timeit, random 

a, b = 1, 3 

lst = numpy.array([random.uniform(0, 5) for _ in xrange(1000)]) 

def numpy_way(): 
    numpy.flatnonzero((lst > 1) & (lst < 3))[:10] 

def list_comprehension(): 
    [e for e in lst if 1 < e < 3][:10] 

print timeit.timeit(numpy_way) 
print timeit.timeit(list_comprehension) 

Wersja numpy wynosi ponad 60 razy szybciej.

+0

Jakie jest porównanie wydajności w porównaniu z robieniem listy? Po co używać 'numpy.flatnonzero' zamiast' numpy.where'? – Seanny123

+1

To ponad 60 razy szybciej w moich rękach. 'flatnonzero' jest prostsze niż' where', tutaj; nie musisz wyciągać tablicy wskaźników z krotki. –

Powiązane problemy