Como encontrar todas as ocorrências de um elemento em uma lista?

378

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?

Bruce
fonte
11
Estou um pouco confuso com esta pergunta: você deseja procurar por um item recursivamente em todos os níveis de uma lista multidimensional ou apenas por ocorrências no nível superior da lista?
Anderson Green
22
Na minha opinião, deve haver um método de lista que faça exatamente isso.
Otocan

Respostas:

545

Você pode usar uma compreensão de lista:

indices = [i for i, x in enumerate(my_list) if x == "whatever"]
Sven Marnach
fonte
3
Nos pitões mais antigos, use filter () para essencialmente a mesma funcionalidade.
Gleno
44
As compreensões de lista apareceram em python em 2.0, enumerateem 2.3. Então, sim, se o seu Python é antigo, use filter().
Steven Rumbalski
2
Essa técnica não encontrará todas as ocorrências de um item em uma matriz multidimensional. Por exemplo, print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])retorna em []vez de [[0, 1], [0, 0], [1, 1]].
Anderson Green
10
@AndersonGreen: O termo "matriz multidimensional" sugere uma estrutura de dados que garante um tamanho uniforme ao longo de cada um de seus eixos. Não existe essa estrutura de dados no Python simples. Há listas de listas, mas elas são muito diferentes de "matrizes multidimensionais". Se você quiser o último, considere usar o NumPy, que permite fazer coisas como (a == 1).nonzero()para uma matriz NumPy a.
Sven Marnach 04/02
2
@ MadmanLee Se você quiser algo rápido, use NumPy. Veja a resposta de JoshAdel
Georgy
117

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.

JoshAdel
fonte
2
Notei que o [0] no final converte o que seria uma matriz em uma string. Estou curioso por que você escolheu fazer isso.
Amelia
5
@amelia [0]é necessária porque whereretorna uma tupla(array([2, 8], dtype=int64),)
Winand
11
Hey, @Winand eu coloquei [0], mas ainda tenho as duas partes. Aqui está o meu código: (nrg.local_logs.all_id_resp_address é uma lista) "ste =" 199.38.164.165 "value = np.where (nrg.local_logs.all_id_resp_address == ste) [0]" Ficarei feliz se você puder dizer -me o que eu fiz de errado
Tomer
2
@ Antes de mais nada all_id_resp_address, np.arraynão deve ser list.
Winand
11
@ Você tentou comparar 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.
Winand
29

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.

Paulo Almeida
fonte
3
Você diz que isso é mais rápido que um comp de lista, pode mostrar seus horários que demonstram isso?
9789 Chris_Rands
5
Isso foi há muito tempo, eu provavelmente usei 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.
Paulo Almeida
18

E se:

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]
NPE
fonte
10
occurrences = lambda s, lst: (i for i,e in enumerate(lst) if e == s)
list(occurrences(1, [1,2,3,1])) # = [0, 3]
phihag
fonte
8

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.

pylang
fonte
11
poderia ser bom se este lib foi adicionado em Conda-forja (embora conda installse transformou muito instável no desempenho ultimamente)
matanster
4

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)
Artsiom Rudzenka
fonte
4

Ou use range(python 3):

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

Para (python 2):

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

E então (ambos os casos):

print(l)

É como esperado.

Sub-10
fonte
4

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]
Niranjan Nagaraju
fonte
2

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)
privatevoid
fonte
2

Obtendo todas as ocorrências e a posição de um ou mais itens (idênticos) em uma lista

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]
>>>

Vamos fazer nossa função findindex

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]

Simples

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

Resultado:

0
4
Giovanni G. PY
fonte
Essa resposta foi a mais fácil de implementar no meu código existente.
Ryan Harris
2

Usando um for-loop:

  • As respostas 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 .
  • crie uma lista vazia, indices
  • crie o loop com 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]
  • no loop, adicione qualquer 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]
  • As funções, 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.

Usando a while-loope .index:

  • Com .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]
Trenton McKinney
fonte
Sua autodefinição get_indeicesé um pouco mais rápida (~ 15%) do que a compreensão normal da lista. Eu estou tentando descobrir isso.
Travis
1

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)
Mr. Xcoder
fonte
1

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]
Denis Rasulev
fonte