2013-05-22 11 views
23

Ho una lunga lista di numeri float che vanno da 1 a 5, chiamati "media", e voglio restituire l'elenco di indici per elementi che sono più piccoli di un o più grande di bTrovare gli indici di elementi corrispondenti nell'elenco in Python

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) 

Ma sorprendentemente, l'uscita per "partite" ha un sacco di ripetizioni in essa, ad esempio, [2, 2, 10, 2, 2, 2, 19, 2, 10, 2, 2, 42, 2, 2, 10, 2, 2, 2, 10, 2, 2, ...].

Perché sta succedendo?

+0

Possibile duplicato di [Come trovare tutte le occorrenze di un elemento in un elenco?] (Https://stackoverflow.com/questions/6294179/how-to-find-all-occurrences-of-an-element-in -a-list) – Qiu

risposta

52

Si sta utilizzando .index() che troverà solo l'occorrenza del proprio valore nell'elenco. Pertanto, se si ha un valore 1.0 nell'indice 2 e nell'indice 9, allora .index(1.0) sarà sempre restituirà 2, non importa quante volte 1.0 si verifica nell'elenco.

Usa enumerate() per aggiungere indici al passante invece:

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

È possibile comprimere questo in una lista di comprensione:

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

Ora capisco perfettamente. La comprensione delle liste è davvero buona, sto ancora cercando di adattarmi a questo tipo di forma compatta in Python. La tua risposta è eccellente, grazie mille! –

+0

La cosa buffa è che il risultato sbagliato con le ripetizioni sembra funzionare bene per il mio uso futuro, dal momento che voglio usarlo per estrarre colonne di una grande matrice. Sembra che le ripetizioni non influiscano sull'affettatura. –

+1

Otterrai comunque i valori corretti fuori dal tuo elenco, gli stessi valori si trovano nell'indice 2 e in qualsiasi indice successivo. Ma è un bug che aspetta di succedere, mordendoti in qualche altro punto del tuo codice. –

-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

Questo non è affatto ciò che l'OP voleva. – TerryA

+0

rileggere la domanda: p – TerryA

+0

Ancora, 'enumerate' è un chiaro vincitore qui :) – root

2

Si tratta di una dipendenza piuttosto pesante, ma se si' Sto facendo un sacco di questo genere di cose che dovresti considerare usando 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]) 

In risposta alla domanda di Seanny123, ho usato questo codice tempistica:

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) 

La versione NumPy è oltre 60 volte più veloce.

+0

Qual è il confronto delle prestazioni rispetto al solo fare una comprensione delle liste? Inoltre, perché usare 'numpy.flatnonzero' su' numpy.where'? – Seanny123

+1

È più di 60 volte più veloce nelle mie mani. 'flatnonzero' è più semplice di' where', qui; non è necessario estrarre la matrice di indici dalla tupla. –

Problemi correlati