index()
poda tylko pierwsze wystąpienie elementu na liście. Czy istnieje fajna sztuczka, która zwraca wszystkie indeksy na liście?
index()
poda tylko pierwsze wystąpienie elementu na liście. Czy istnieje fajna sztuczka, która zwraca wszystkie indeksy na liście?
Odpowiedzi:
Możesz użyć rozumienia listy:
indices = [i for i, x in enumerate(my_list) if x == "whatever"]
enumerate
w wersji 2.3. Więc tak, jeśli twój Python jest starożytny, użyj filter()
.
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 NumPy a
.
Chociaż nie jest to rozwiązanie dla list bezpośrednio, numpy
naprawdę 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ń.
[0]
jest potrzebna, ponieważ where
zwraca krotkę(array([2, 8], dtype=int64),)
all_id_resp_address
powinna być np.array
nie list
.
list
i str
, oczywiście zdałeś False
do np.where
. Gdy np.array
porównasz z czymś otrzymujesz tablicę wartości boolowskich. Następnie np.where
znajduje pozycje wszystkich True
wartości tej tablicy.
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 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.
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.
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_itertools
to biblioteka innej firmy > pip install more_itertools
.
conda install
ostatnio stał się bardzo niestabilny w działaniu)
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)
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.
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]
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)
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]
>>>
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]
for n, i in enumerate([1, 2, 3, 4, 1]):
if i == 1:
print(n)
Wynik:
0
4
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
, 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]
get_indices
są zaimplementowane z podpowiedziami typu . W tym przypadku lista n
jest zbiorem int
s, dlatego szukamy value
, zdefiniowanego również jako int
.while-loop
i .index
:.index
użyj try-except
do obsługi błędów, ponieważ ValueError
wystąpi, jeśli value
nie 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]
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:
f = lambda my_list, value:filter(lambda x: my_list[x] == value, range(len(my_list)))
Gdzie my_list
jest lista, dla której chcesz uzyskać indeksy, i value
szukana wartość. Stosowanie:
f(some_list, some_element)
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]