index()
darà solo la prima occorrenza di un elemento in un elenco. Esiste un trucco accurato che restituisce tutti gli indici in un elenco?
index()
darà solo la prima occorrenza di un elemento in un elenco. Esiste un trucco accurato che restituisce tutti gli indici in un elenco?
Risposte:
È possibile utilizzare una comprensione dell'elenco:
indices = [i for i, x in enumerate(my_list) if x == "whatever"]
enumerate
a 2.3. Quindi sì, se il tuo Python è antico, usa filter()
.
print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])
restituisce []
invece di [[0, 1], [0, 0], [1, 1]]
.
(a == 1).nonzero()
per un array NumPy a
.
Pur non essendo una soluzione per le liste direttamente, numpy
brilla 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.
[0]
è necessaria perché where
restituisce una tupla(array([2, 8], dtype=int64),)
all_id_resp_address
dovrebbe essere np.array
non list
.
list
e str
, ovviamente, sei passato False
a np.where
. Quando si confronta np.array
con smth. ottieni una matrice di valori booleani. Quindi np.where
trova le posizioni di tutti i True
valori di quell'array.
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 numpy
soluzione 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.
timeit.timeit
con 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.
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
.
conda install
ultimamente è diventata molto instabile nelle prestazioni)
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)
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
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]
È 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)
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]
>>>
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]
for n, i in enumerate([1, 2, 3, 4, 1]):
if i == 1:
print(n)
Produzione:
0
4
for-loop
:enumerate
e 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 .indices
for i in range(len(x)):
, che essenzialmente scorre attraverso un elenco di posizioni di indice[0, 1, 2, 3, ..., len(x)-1]
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]
get_indices
sono implementate con suggerimenti sul tipo . In questo caso, l'elenco, n
è un gruppo di int
s, quindi cerchiamo value
, definito anche come int
.while-loop
e .index
:.index
, utilizzare try-except
per la gestione degli errori perché ValueError
si verificherà a se value
non è 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]
get_indeices
è un po 'più veloce (~ 15%) rispetto alla normale comprensione dell'elenco. Sto cercando di capirlo.
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_list
la lista di cui vuoi ottenere gli indici, ed value
è il valore cercato. Uso:
f(some_list, some_element)
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]