index()apenas fornecerá a primeira ocorrência de um item em uma lista. Existe um truque interessante que retorna todos os índices em uma lista?
index()apenas fornecerá a primeira ocorrência de um item em uma lista. Existe um truque interessante que retorna todos os índices em uma lista?
Respostas:
Você pode usar uma compreensão de lista:
indices = [i for i, x in enumerate(my_list) if x == "whatever"]
enumerateem 2.3. Então, sim, se o seu Python é antigo, use filter().
print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])retorna em []vez de [[0, 1], [0, 0], [1, 1]].
(a == 1).nonzero()para uma matriz NumPy a.
Embora não seja uma solução para listas diretamente, numpyrealmente brilha para esse tipo de coisa:
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]
retorna:
ii ==>array([2, 8])
Isso pode ser significativamente mais rápido para listas (matrizes) com um grande número de elementos versus algumas das outras soluções.
[0]é necessária porque whereretorna uma tupla(array([2, 8], dtype=int64),)
all_id_resp_address, np.arraynão deve ser list.
liste str, obviamente, passou Falsepara np.where. Quando você compara np.arraycom smth. você obtém uma matriz de valores booleanos. Em seguida, np.wherelocaliza as posições de todos os Truevalores dessa matriz.
Uma solução usando 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)
É muito mais rápido do que a compreensão da lista enumerate, para listas grandes. Também é muito mais lento que a numpysolução, se você já possui a matriz, caso contrário, o custo da conversão supera o ganho de velocidade (testado em listas inteiras com 100, 1000 e 10000 elementos).
NOTA: Uma nota de cautela com base no comentário de Chris_Rands: esta solução é mais rápida que a compreensão da lista se os resultados forem suficientemente escassos, mas se a lista tiver muitas instâncias do elemento que está sendo pesquisado (mais de ~ 15% da lista , em um teste com uma lista de 1000 números inteiros), a compreensão da lista é mais rápida.
timeit.timeitcom listas geradas aleatoriamente. Esse é um ponto importante, e suponho que seja por isso que você pergunta. Na época, isso não me ocorreu, mas os ganhos de velocidade só são verdadeiros se os resultados forem suficientemente escassos. Acabei de testar com uma lista cheia do elemento a ser pesquisado e é muito mais lento que a compreensão da lista.
more_itertools.locate localiza índices para todos os itens que satisfazem uma condição.
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é uma biblioteca de terceiros > pip install more_itertools.
conda installse transformou muito instável no desempenho ultimamente)
Mais uma solução (desculpe se duplicadas) para todas as ocorrências:
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)
Usando filter () em 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]
Você pode criar um padrão
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)
Com enumerate (alist), você pode armazenar o primeiro elemento (n) que é o índice da lista quando o elemento x é igual ao que você procura.
>>> alist = ['foo', 'spam', 'egg', 'foo']
>>> foo_indexes = [n for n,x in enumerate(alist) if x=='foo']
>>> foo_indexes
[0, 3]
>>>
Essa função pega o item e a lista como argumentos e retorna a posição do item na lista, como vimos anteriormente.
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"))
Resultado
[1, 3, 5, 7]
for n, i in enumerate([1, 2, 3, 4, 1]):
if i == 1:
print(n)
Resultado:
0
4
for-loop:enumeratee a compreensão de uma lista são mais eficientes e pitônicas, no entanto, essa resposta é direcionada a estudantes que talvez não tenham permissão para usar algumas dessas funções internas .indicesfor i in range(len(x)): , que itera essencialmente através de uma lista de locais de índice[0, 1, 2, 3, ..., len(x)-1]i, onde x[i]é uma correspondência value, paraindices
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_indicessão implementadas com dicas de tipo . Nesse caso, a lista n,, é um monte de ints, portanto, procuramos por value, também definido como um int.while-loope .index:.index, use try-exceptpara tratamento de erros, pois ValueErrorocorrerá um se valuenão estiver na lista.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é um pouco mais rápida (~ 15%) do que a compreensão normal da lista. Eu estou tentando descobrir isso.
Se você estiver usando o Python 2, poderá obter a mesma funcionalidade com isso:
f = lambda my_list, value:filter(lambda x: my_list[x] == value, range(len(my_list)))
Onde my_listestá a lista da qual você deseja obter os índices e valueo valor pesquisado. Uso:
f(some_list, some_element)
Se você precisar procurar todas as posições de elementos entre determinados índices , poderá indicá-los:
[i for i,x in enumerate([1,2,3,2]) if x==2 & 2<= i <=3] # -> [3]