Bir listedeki bir öğenin tüm oluşumlarını nasıl bulurum?


378

index()yalnızca listedeki bir öğenin ilk oluşumunu verecektir. Bir listedeki tüm indeksleri döndüren düzgün bir hile var mı?


1
Bu soru ile biraz kafam karıştı: Bir öğeyi çok boyutlu bir listenin tüm düzeylerinde özyinelemeli olarak mı aramak istiyorsunuz yoksa yalnızca listenin en üst düzeyindeki olayları mı aramak istiyorsunuz?
Anderson Green

22
Bence tam olarak bunu yapan bir liste yöntemi olmalı.
otocan

Yanıtlar:


545

Bir liste kavrayışı kullanabilirsiniz:

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

3
Eski pitonlarda, temel olarak aynı işlevsellik için filter () kullanın.
Gleno

44
Liste kavrayışları python'da 2.0'da, enumerate2.3'te ortaya çıktı. Yani evet, Python'unuz eskiyse kullanın filter().
Steven Rumbalski

2
Bu teknik, bir öğenin tüm boyutlarını çok boyutlu bir dizide bulamaz. Örneğin, yerine print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])döner . [][[0, 1], [0, 0], [1, 1]]
Anderson Green

10
@AndersonGreen: "Çok boyutlu dizi" terimi, her bir ekseni boyunca tek biçimli boyuta sahip olması garanti edilen bir veri yapısı önerir. Düz Python'da böyle bir veri yapısı yoktur. Liste listeleri var, ama bunlar "çok boyutlu dizilerden" çok farklı. İkincisini istiyorsanız, (a == 1).nonzero()NumPy dizisi gibi şeyler yapmanıza izin veren NumPy'yi kullanmayı düşünmelisiniz a.
Sven Marnach

2
@MadmanLee Hızlı bir şey istiyorsanız, NumPy'yi kullanın. Cevabını bakın JoshAdel
Georgy

117

Doğrudan listeler için bir çözüm olmasa da, numpybu tür şeyler için gerçekten parlıyor:

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]

İadeler:

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

Bu, diğer bazı çözümlere kıyasla çok sayıda öğeye sahip listeler (diziler) için daha hızlı olabilir.


2
Sonunda [0] bir dizeye bir dizi ne dönüştürür fark ettim. Bunu neden seçtiğini merak ediyorum.
amelia

5
@amelia [0]Çünkü ihtiyaç duyulan wheregetiriler bir demet(array([2, 8], dtype=int64),)
Winand

1
Hey @Winand [0] yazdım ama yine de iki parçayı da alıyorum. İşte benim kod: (nrg.local_logs.all_id_resp_address bir liste) "ste =" 199.38.164.165 "value = np.where (nrg.local_logs.all_id_resp_address == ste) [0]" bana yanlış yaptığım şey
Tomer

2
@Tomer şeyden önce all_id_resp_addressolmalıdır np.arraydeğil list.
Winand

1
Karşılaştırmak çalıştı @Tomer listve straçıkçası geçtin Falseiçin np.where. np.arrayİkram etmekle kıyaslandığında . bir dizi boolean değer elde edersiniz. Sonra o dizinin np.wheretüm Truedeğerlerinin konumlarını bulur .
Winand

29

Kullanarak bir çözüm 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)

enumerateBüyük listeler için liste kavrayışından çok daha hızlıdır . Bu daha yavaş daha da numpyçözelti halinde önceden dizi başka türlü hızlı kazanç daha ağır basar dönüştürme maliyeti (100, 1000 ve 10000 elemanları tamsayı listelerinde test edilmiştir).

NOT: Chris_Rands'ın yorumuna dayanan bir uyarı notu: sonuçlar yeterince seyrek ise, ancak liste aranan öğenin birçok örneğine sahipse (listenin ~% 15'inden fazlası) bu çözüm liste kavramadan daha hızlıdır , 1000 tamsayı içeren bir testte) liste kavraması daha hızlıdır.


3
Bunun bir liste kompozisyonundan daha hızlı olduğunu söylüyorsunuz, bunu gösteren zamanlamalarınızı gösterebilir misiniz?
Chris_Rands

5
Bu uzun zaman önceydi, muhtemelen timeit.timeitrastgele oluşturulmuş listelerle kullandım. Yine de bu önemli bir nokta ve sanırım bu yüzden sordunuz. O zaman bana gelmedi, ancak hız kazanımları sadece sonuçlar yeterince seyrek ise doğrudur. Sadece aranacak unsurla dolu bir listeyle test ettim ve liste kavrayışından çok daha yavaş.
Paulo Almeida

18

Nasıl olur:

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 bir koşulu karşılayan tüm öğeler için endeksler bulur.

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üçüncü taraf bir kütüphanedir > pip install more_itertools.


1
Bu lib conda-forge'a eklendiyse iyi olabilir ( conda installson zamanlarda performansta çok kararsız hale gelmiş olsa da)
matanster

4

Tüm oluşumlar için bir çözüm daha (yinelenirse özür dilerim):

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

Veya Kullan range(python 3):

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

(Python 2) için:

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

Ve sonra (her iki durumda):

print(l)

Beklendiği gibi.


4

Python2'de filter () kullanımı.

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

Bir varsayılan karar oluşturabilirsiniz

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

Bir listedeki bir veya daha fazla (özdeş) öğenin tüm oluşumlarını ve konumunu alma

Numaralandırma (alist) ile, x öğesi aradığınız şeye eşit olduğunda listenin dizini olan ilk öğeyi (n) saklayabilirsiniz.

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

Fonksiyonumuzu findindex yapalım

Bu işlev, öğeyi ve listeyi bağımsız değişken olarak alır ve öğenin daha önce gördüğümüz gibi listedeki konumunu döndürür.

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

Çıktı


[1, 3, 5, 7]

Basit

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

Çıktı:

0
4

Bu cevap, benim mevcut koduma uygulamak için en kolay oldu.
Ryan Harris

2

Kullanarak for-loop:

  • Yanıtlar enumerateve liste kavrayışı daha verimli ve pitoniktir, ancak bu yanıt, bu yerleşik işlevlerin bazılarını kullanmasına izin verilmeyen öğrencileri hedefler .
  • boş bir liste oluşturun, indices
  • for i in range(len(x)):temel olarak bir dizin konumları listesi üzerinden yinelenen bir döngü oluşturun[0, 1, 2, 3, ..., len(x)-1]
  • döngüde herhangi eklemek inerede, x[i]bir maç olduğunu value, hiç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]
  • Fonksiyonlar, get_indicesile uygulanan tip ipuçları . Bu durumda, liste, nbir grup ints'dir, bu nedenle valuede bir int.

A while-loopve .index:

  • İle .index, listede yer almazsa bir hata oluşacağı try-exceptiçin hata işleme için kullanın .ValueErrorvalue
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]

Kendi tanımlamanız get_indeicesnormal liste anlamadan biraz daha hızlıdır (~% 15). Anlamaya çalışıyorum.
Travis

1

Python 2 kullanıyorsanız, bununla aynı işlevselliği elde edebilirsiniz:

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

my_listDizinlerini almak istediğiniz liste nerede ve valuearanan değerdir. Kullanımı:

f(some_list, some_element)

1

Belirli dizinler arasındaki tüm öğelerin konumlarını aramanız gerekirse, bunları belirtebilirsiniz:

[i for i,x in enumerate([1,2,3,2]) if x==2 & 2<= i <=3] # -> [3]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.