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"]
enumerate
em 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, numpy
realmente 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 where
retorna uma tupla(array([2, 8], dtype=int64),)
all_id_resp_address
, np.array
não deve ser list
.
list
e str
, obviamente, passou False
para np.where
. Quando você compara np.array
com smth. você obtém uma matriz de valores booleanos. Em seguida, np.where
localiza as posições de todos os True
valores 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 numpy
soluçã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.timeit
com 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 install
se 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
:enumerate
e 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 .indices
for 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_indices
são implementadas com dicas de tipo . Nesse caso, a lista n
,, é um monte de int
s, portanto, procuramos por value
, também definido como um int
.while-loop
e .index
:.index
, use try-except
para tratamento de erros, pois ValueError
ocorrerá um se value
nã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_list
está a lista da qual você deseja obter os índices e value
o 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]