Jak znaleźć wszystkie wystąpienia elementu na liście?


377

index()poda tylko pierwsze wystąpienie elementu na liście. Czy istnieje fajna sztuczka, która zwraca wszystkie indeksy na liście?


1
Jestem nieco zdezorientowany tym pytaniem: czy chcesz wyszukać element rekurencyjnie na wszystkich poziomach listy wielowymiarowej, czy chcesz wyszukać tylko wystąpienia na najwyższym poziomie listy?
Anderson Green,

22
Moim zdaniem powinna istnieć metoda listowa, która właśnie to robi.
otocan

Odpowiedzi:


544

Możesz użyć rozumienia listy:

indices = [i for i, x in enumerate(my_list) if x == "whatever"]

3
Na starszych pytonach użyj filter () dla zasadniczo tej samej funkcjonalności.
Gleno,

44
Wyjaśnienia list pojawiły się w Pythonie w wersji 2.0, enumeratew wersji 2.3. Więc tak, jeśli twój Python jest starożytny, użyj filter().
Steven Rumbalski,

2
Ta technika nie znajdzie wszystkich wystąpień elementu w tablicy wielowymiarowej. Na przykład print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])zwraca []zamiast [[0, 1], [0, 0], [1, 1]].
Anderson Green

9
@AndersonGreen: Termin „tablica wielowymiarowa” sugeruje strukturę danych, która gwarantuje jednolity rozmiar wzdłuż każdej ze swoich osi. W zwykłym języku Python nie ma takiej struktury danych. Istnieją listy list, ale różnią się one bardzo od „tablic wielowymiarowych”. Jeśli chcesz tego drugiego, powinieneś rozważyć użycie NumPy, co pozwala robić rzeczy takie jak (a == 1).nonzero()dla tablicy NumPy a.
Sven Marnach

2
@MadmanLee Jeśli chcesz czegoś szybko, użyj NumPy. Zobacz odpowiedź JoshAdela
Georgy

117

Chociaż nie jest to rozwiązanie dla list bezpośrednio, numpynaprawdę błyszczy dla tego rodzaju rzeczy:

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]

zwroty:

ii ==>array([2, 8])

Może to być znacznie szybsze w przypadku list (tablic) z dużą liczbą elementów w porównaniu do niektórych innych rozwiązań.


2
Zauważyłem, że [0] na końcu konwertuje tablicę na ciąg znaków. Jestem ciekawy, dlaczego to zrobiłeś.
amelia,

5
@amelia [0]jest potrzebna, ponieważ wherezwraca krotkę(array([2, 8], dtype=int64),)
Winand

1
Hej @ Winin Włożyłem [0], ale wciąż dostaję obie części. Oto mój kod: (nrg.local_logs.all_id_resp_address to lista) "ste =" 199.38.164.165 "wartość = np.where (nrg.local_logs.all_id_resp_address == ste) [0]" Będę szczęśliwy, jeśli możesz powiedzieć mi to, co zrobiłem źle
Tomer

2
@Tomer przede wszystkim all_id_resp_addresspowinna być np.arraynie list.
Winand,

1
@Tomer próbowano porównać listi str, oczywiście zdałeś Falsedo np.where. Gdy np.arrayporównasz z czymś otrzymujesz tablicę wartości boolowskich. Następnie np.whereznajduje pozycje wszystkich Truewartości tej tablicy.
Winand,

29

Rozwiązanie wykorzystujące 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)

W enumerateprzypadku dużych list jest znacznie szybszy niż zrozumienie listy. Jest również znacznie wolniejszy niż numpyrozwiązanie, jeśli masz już tablicę, w przeciwnym razie koszt konwersji przewyższa wzrost prędkości (testowany na listach całkowitych zawierających 100, 1000 i 10000 elementów).

UWAGA: Uwaga ostrożna w oparciu o komentarz Chris_Rands: to rozwiązanie jest szybsze niż zrozumienie listy, jeśli wyniki są wystarczająco rzadkie, ale jeśli lista zawiera wiele instancji wyszukiwanego elementu (więcej niż ~ 15% listy , w teście z listą 1000 liczb całkowitych), zrozumienie listy jest szybsze.


3
Mówisz, że to jest szybsze niż porównanie z listą, czy możesz pokazać swoje czasy, które to pokazują?
Chris_Rands

4
To było dawno temu, prawdopodobnie korzystałem timeit.timeitz losowo generowanych list. To ważna kwestia i przypuszczam, że właśnie dlatego pytasz. W tym czasie nie przyszło mi to do głowy, ale przyrosty prędkości są prawdziwe tylko wtedy, gdy wyniki są wystarczająco rzadkie. Właśnie przetestowałem z listą pełną elementu do wyszukania, i jest to znacznie wolniejsze niż zrozumienie listy.
Paulo Almeida,

18

Co powiesz na:

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 znajduje indeksy dla wszystkich przedmiotów, które spełniają warunek.

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_itertoolsto biblioteka innej firmy > pip install more_itertools.


1
może być miło, gdyby ten lib został dodany do Conda-Forge (choć conda installostatnio stał się bardzo niestabilny w działaniu)
Matanster

4

Jeszcze jedno rozwiązanie (przepraszam, jeśli duplikaty) dla wszystkich wystąpień:

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

Lub użyj range(python 3):

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

Dla (python 2):

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

A następnie (oba przypadki):

print(l)

Jest zgodnie z oczekiwaniami.


4

Używanie filter () w 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

Możesz utworzyć defaultdict

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

Uzyskiwanie wszystkich wystąpień i pozycji jednego lub więcej (identycznych) elementów na liście

Za pomocą enumerate (alist) możesz zapisać pierwszy element (n), który jest indeksem listy, gdy element x jest równy temu, czego szukasz.

>>> alist = ['foo', 'spam', 'egg', 'foo']
>>> foo_indexes = [n for n,x in enumerate(alist) if x=='foo']
>>> foo_indexes
[0, 3]
>>>

Zróbmy naszą funkcję findindex

Ta funkcja przyjmuje argument i listę jako argumenty i zwraca pozycję elementu na liście, jak widzieliśmy wcześniej.

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

Wynik


[1, 3, 5, 7]

Prosty

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

Wynik:

0
4

Ta odpowiedź była dla mnie najłatwiejsza do zaimplementowania w istniejącym kodzie.
Ryan Harris

2

Korzystanie z for-loop:

  • Odpowiedzi na pytania enumeratei lista są bardziej wydajne i pytoniczne, jednak odpowiedź ta jest skierowana do studentów, którzy mogą nie mieć dostępu do niektórych z tych wbudowanych funkcji .
  • utwórz pustą listę, indices
  • utwórz pętlę for i in range(len(x)):, która zasadniczo iteruje przez listę lokalizacji indeksu[0, 1, 2, 3, ..., len(x)-1]
  • w pętli dodaj dowolne i, gdzie x[i]pasuje do value,indices
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]
  • Funkcje,, get_indicessą zaimplementowane z podpowiedziami typu . W tym przypadku lista njest zbiorem ints, dlatego szukamy value, zdefiniowanego również jako int.

Używając a while-loopi .index:

  • Z .indexużyj try-exceptdo obsługi błędów, ponieważ ValueErrorwystąpi, jeśli valuenie ma jej na liście.
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]

Samookreślenie get_indeicesjest nieco szybsze (~ 15%) niż zwykłe rozumienie listy. Próbuję to rozgryźć.
Travis

1

Jeśli używasz języka Python 2, możesz osiągnąć tę samą funkcjonalność dzięki:

f = lambda my_list, value:filter(lambda x: my_list[x] == value, range(len(my_list)))

Gdzie my_listjest lista, dla której chcesz uzyskać indeksy, i valueszukana wartość. Stosowanie:

f(some_list, some_element)

1

Jeśli potrzebujesz wyszukać wszystkie pozycje elementu między niektórymi indeksami , możesz podać je:

[i for i,x in enumerate([1,2,3,2]) if x==2 & 2<= i <=3] # -> [3]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.