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"]
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ń.
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 =-1whileTrue:try:
offset = lst.index(element, offset+1)exceptValueError: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.
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]
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)
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 =0whileTrue: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 +=1exceptValueErroras e:breakreturn indices
print(get_indices(n,-60))>>>[4,8,9]
Odpowiedzi:
Możesz użyć rozumienia listy:
źródło
enumerate
w wersji 2.3. Więc tak, jeśli twój Python jest starożytny, użyjfilter()
.print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])
zwraca[]
zamiast[[0, 1], [0, 0], [1, 1]]
.(a == 1).nonzero()
dla tablicy NumPya
.Chociaż nie jest to rozwiązanie dla list bezpośrednio,
numpy
naprawdę błyszczy dla tego rodzaju rzeczy:zwroty:
Może to być znacznie szybsze w przypadku list (tablic) z dużą liczbą elementów w porównaniu do niektórych innych rozwiązań.
źródło
[0]
jest potrzebna, ponieważwhere
zwraca krotkę(array([2, 8], dtype=int64),)
all_id_resp_address
powinna byćnp.array
nielist
.list
istr
, oczywiście zdałeśFalse
donp.where
. Gdynp.array
porównasz z czymś otrzymujesz tablicę wartości boolowskich. Następnienp.where
znajduje pozycje wszystkichTrue
wartości tej tablicy.Rozwiązanie wykorzystujące
list.index
:W
enumerate
przypadku dużych list jest znacznie szybszy niż zrozumienie listy. Jest również znacznie wolniejszy niżnumpy
rozwią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.
źródło
timeit.timeit
z 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.Co powiesz na:
źródło
źródło
more_itertools.locate
znajduje indeksy dla wszystkich przedmiotów, które spełniają warunek.more_itertools
to biblioteka innej firmy> pip install more_itertools
.źródło
conda install
ostatnio stał się bardzo niestabilny w działaniu)Jeszcze jedno rozwiązanie (przepraszam, jeśli duplikaty) dla wszystkich wystąpień:
źródło
Lub użyj
range
(python 3):Dla (python 2):
A następnie (oba przypadki):
Jest zgodnie z oczekiwaniami.
źródło
Używanie filter () w python2.
źródło
Możesz utworzyć defaultdict
źródło
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.
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.
Wynik
Prosty
Wynik:
źródło
Korzystanie z
for-loop
:enumerate
i 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 .indices
for i in range(len(x)):
, która zasadniczo iteruje przez listę lokalizacji indeksu[0, 1, 2, 3, ..., len(x)-1]
i
, gdziex[i]
pasuje dovalue
,indices
x[i]
uzyskuje dostęp do listy według indeksuget_indices
są zaimplementowane z podpowiedziami typu . W tym przypadku listan
jest zbioremint
s, dlatego szukamyvalue
, zdefiniowanego również jakoint
.Używając a
while-loop
i.index
:.index
użyjtry-except
do obsługi błędów, ponieważValueError
wystąpi, jeślivalue
nie ma jej na liście.źródło
get_indeices
jest nieco szybsze (~ 15%) niż zwykłe rozumienie listy. Próbuję to rozgryźć.Jeśli używasz języka Python 2, możesz osiągnąć tę samą funkcjonalność dzięki:
Gdzie
my_list
jest lista, dla której chcesz uzyskać indeksy, ivalue
szukana wartość. Stosowanie:źródło
Jeśli potrzebujesz wyszukać wszystkie pozycje elementu między niektórymi indeksami , możesz podać je:
źródło