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?


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

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.


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.


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]

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


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)

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.


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]

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)

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

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]

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)

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]
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.