Come trovare tutte le occorrenze di un elemento in un elenco?


378

index()darà solo la prima occorrenza di un elemento in un elenco. Esiste un trucco accurato che restituisce tutti gli indici in un elenco?


1
Sono un po 'confuso da questa domanda: vuoi cercare un elemento in modo ricorsivo in tutti i livelli di un elenco multidimensionale o vuoi solo cercare le occorrenze nel livello superiore dell'elenco?
Anderson Green,

22
Secondo me dovrebbe esserci un metodo di lista che fa esattamente questo.
otocan,

Risposte:


545

È possibile utilizzare una comprensione dell'elenco:

indices = [i for i, x in enumerate(my_list) if x == "whatever"]

3
Sui pitoni più vecchi, usa filter () per la stessa funzionalità.
Gleno,

44
Comprensioni delle liste mostrate in Python a 2.0, enumeratea 2.3. Quindi sì, se il tuo Python è antico, usa filter().
Steven Rumbalski,

2
Questa tecnica non trova tutte le occorrenze di un elemento in un array multidimensionale. Ad esempio, print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])restituisce []invece di [[0, 1], [0, 0], [1, 1]].
Anderson Green,

10
@AndersonGreen: il termine "array multidimensionale" indica una struttura di dati che garantisce dimensioni uniformi lungo ciascuno dei suoi assi. Non esiste una tale struttura di dati in Python semplice. Ci sono elenchi di elenchi, ma sono molto diversi dagli "array multidimensionali". Se vuoi quest'ultimo, dovresti considerare l'utilizzo di NumPy, che ti consente di fare cose come (a == 1).nonzero()per un array NumPy a.
Sven Marnach,

2
@MadmanLee Se vuoi qualcosa di veloce, usa NumPy. Vedi la risposta di JoshAdel
Georgy,

117

Pur non essendo una soluzione per le liste direttamente, numpybrilla davvero per questo genere di cose:

import numpy as np
values = np.array([1,2,3,1,2,4,5,6,3,2,1])
searchval = 3
ii = np.where(values == searchval)[0]

ritorna:

ii ==>array([2, 8])

Questo può essere significativamente più veloce per gli elenchi (array) con un gran numero di elementi rispetto ad alcune delle altre soluzioni.


2
Ho notato che [0] alla fine converte quello che sarebbe un array in una stringa. Sono curioso di sapere perché hai scelto di farlo.
amelia,

5
@amelia [0]è necessaria perché whererestituisce una tupla(array([2, 8], dtype=int64),)
Winand

1
Ehi, @Winand, ho inserito [0] ma ho ancora entrambe le parti. Ecco il mio codice: (nrg.local_logs.all_id_resp_address è un elenco) "ste =" 199.38.164.165 "value = np.where (nrg.local_logs.all_id_resp_address == ste) [0]" Sarò felice se puoi dirlo quello che ho fatto di sbagliato
Tomer,

2
@Tomer prima di tutto all_id_resp_addressdovrebbe essere np.arraynon list.
Vinci il

1
@Tomer hai provato a confrontare liste str, ovviamente, sei passato Falsea np.where. Quando si confronta np.arraycon smth. ottieni una matrice di valori booleani. Quindi np.wheretrova le posizioni di tutti i Truevalori di quell'array.
Vinci il

29

Una soluzione che utilizza list.index:

def indices(lst, element):
    result = []
    offset = -1
    while True:
        try:
            offset = lst.index(element, offset+1)
        except ValueError:
            return result
        result.append(offset)

È molto più veloce della comprensione dell'elenco con enumerate, per elenchi di grandi dimensioni. È anche molto più lento della numpysoluzione se si dispone già dell'array, altrimenti il ​​costo della conversione supera il guadagno di velocità (testato su elenchi di numeri interi con 100, 1000 e 10000 elementi).

NOTA: una nota di cautela basata sul commento di Chris_Rands: questa soluzione è più veloce della comprensione dell'elenco se i risultati sono sufficientemente sparsi, ma se l'elenco ha molte istanze dell'elemento cercato (oltre il 15% circa dell'elenco) , su un test con un elenco di 1000 numeri interi), la comprensione dell'elenco è più veloce.


3
Dici che questo è più veloce di un elenco comp, puoi mostrare i tuoi tempi che lo dimostrano?
Chris_Rands

5
Questo è stato molto tempo fa, probabilmente ho usato timeit.timeitcon elenchi generati casualmente. Questo è un punto importante, e suppongo che potrebbe essere il motivo per cui lo chiedi. Al momento non mi è venuto in mente, ma i guadagni di velocità sono veri solo se i risultati sono sufficientemente scarsi. Ho appena provato con un elenco pieno dell'elemento da cercare ed è molto più lento della comprensione dell'elenco.
Paulo Almeida,

18

Che ne dite di:

In [1]: l=[1,2,3,4,3,2,5,6,7]

In [2]: [i for i,val in enumerate(l) if val==3]
Out[2]: [2, 4]

10
occurrences = lambda s, lst: (i for i,e in enumerate(lst) if e == s)
list(occurrences(1, [1,2,3,1])) # = [0, 3]

8

more_itertools.locate trova gli indici per tutti gli articoli che soddisfano una condizione.

from more_itertools import locate


list(locate([0, 1, 1, 0, 1, 0, 0]))
# [1, 2, 4]

list(locate(['a', 'b', 'c', 'b'], lambda x: x == 'b'))
# [1, 3]

more_itertoolsè una libreria di terze parti > pip install more_itertools.


1
potrebbe essere bello se questa lib fosse aggiunta a conda-forge (anche se conda installultimamente è diventata molto instabile nelle prestazioni)
matanster

4

Un'altra soluzione (scusate se duplicati) per tutte le occorrenze:

values = [1,2,3,1,2,4,5,6,3,2,1]
map(lambda val: (val, [i for i in xrange(len(values)) if values[i] == val]), values)

4

Oppure usa range(python 3):

l=[i for i in range(len(lst)) if lst[i]=='something...']

Per (python 2):

l=[i for i in xrange(len(lst)) if lst[i]=='something...']

E poi (entrambi i casi):

print(l)

È come previsto


4

Utilizzando filter () in python2.

>>> q = ['Yeehaw', 'Yeehaw', 'Googol', 'B9', 'Googol', 'NSM', 'B9', 'NSM', 'Dont Ask', 'Googol']
>>> filter(lambda i: q[i]=="Googol", range(len(q)))
[2, 4, 9]

2

È possibile creare un valore predefinito

from collections import defaultdict
d1 = defaultdict(int)      # defaults to 0 values for keys
unq = set(lst1)              # lst1 = [1, 2, 2, 3, 4, 1, 2, 7]
for each in unq:
      d1[each] = lst1.count(each)
else:
      print(d1)

2

Ottenere tutte le occorrenze e la posizione di uno o più elementi (identici) in un elenco

Con enumerate (alist) puoi memorizzare il primo elemento (n) che è l'indice dell'elenco quando l'elemento x è uguale a quello che cerchi.

>>> alist = ['foo', 'spam', 'egg', 'foo']
>>> foo_indexes = [n for n,x in enumerate(alist) if x=='foo']
>>> foo_indexes
[0, 3]
>>>

Facciamo trovare la nostra funzione findindex

Questa funzione prende l'oggetto e l'elenco come argomenti e restituisce la posizione dell'oggetto nell'elenco, come abbiamo visto prima.

def indexlist(item2find, list_or_string):
  "Returns all indexes of an item in a list or a string"
  return [n for n,item in enumerate(list_or_string) if item==item2find]

print(indexlist("1", "010101010"))

Produzione


[1, 3, 5, 7]

Semplice

for n, i in enumerate([1, 2, 3, 4, 1]):
    if i == 1:
        print(n)

Produzione:

0
4

Questa risposta è stata la più semplice da implementare nel mio codice esistente.
Ryan Harris,

2

Utilizzando un for-loop:

  • Le risposte con enumeratee una comprensione dell'elenco sono più efficienti e pitoniche, tuttavia, questa risposta è rivolta agli studenti che potrebbero non essere autorizzati a utilizzare alcune di quelle funzioni integrate .
  • crea un elenco vuoto, indices
  • crea il ciclo con for i in range(len(x)):, che essenzialmente scorre attraverso un elenco di posizioni di indice[0, 1, 2, 3, ..., len(x)-1]
  • nel loop, aggiungi any i, where x[i]is a match to value, aindices
def get_indices(x: list, value: int) -> list:
    indices = list()
    for i in range(len(x)):
        if x[i] == value:
            indices.append(i)
    return indices

n = [1, 2, 3, -50, -60, 0, 6, 9, -60, -60]
print(get_indices(n, -60))

>>> [4, 8, 9]
  • Le funzioni get_indicessono implementate con suggerimenti sul tipo . In questo caso, l'elenco, nè un gruppo di ints, quindi cerchiamo value, definito anche come int.

Utilizzando a while-loope .index:

  • Con .index, utilizzare try-exceptper la gestione degli errori perché ValueErrorsi verificherà a se valuenon è nell'elenco.
def get_indices(x: list, value: int) -> list:
    indices = list()
    i = 0
    while True:
        try:
            # find an occurrence of value and update i to that index
            i = x.index(value, i)
            # add i to the list
            indices.append(i)
            # advance i by 1
            i += 1
        except ValueError as e:
            break
    return indices

print(get_indices(n, -60))
>>> [4, 8, 9]

L'auto-definizione get_indeicesè un po 'più veloce (~ 15%) rispetto alla normale comprensione dell'elenco. Sto cercando di capirlo.
Travis

1

Se stai usando Python 2, puoi ottenere la stessa funzionalità con questo:

f = lambda my_list, value:filter(lambda x: my_list[x] == value, range(len(my_list)))

Dov'è my_listla lista di cui vuoi ottenere gli indici, ed valueè il valore cercato. Uso:

f(some_list, some_element)

1

Se è necessario cercare tutte le posizioni degli elementi tra determinati indici , è possibile dichiararli:

[i for i,x in enumerate([1,2,3,2]) if x==2 & 2<= i <=3] # -> [3]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.