Python: Listede bul


586

Buna rastladım:

item = someSortOfSelection()
if item in myList:
    doMySpecialFunction(item)

ancak bazen tüm öğelerimle çalışmaz, sanki listede tanınmadılar (bir dize listesi olduğunda).

Bu, listedeki bir öğeyi bulmanın en 'pitonik' yolu if x in l:mu?


3
Bu gayet iyi ve eğer öğe içindeki elemanlardan birine eşitse işe yarayacak myList.
Niklas

1
bir şeyler yapmanın iyi bir yolu mu demek istiyorsun? benim birkaç denemede, belki boşluklar vardı ve satır beslemeleri intereferring ... ben sadece "listede bulmak" (genel olarak) uygulamak için iyi bir yol olduğundan emin olmak istedim (genel olarak)
Stephane Rolland

Yanıtlar:


1174

İlk sorunuza gelince: bu kod gayet iyi durumdadır ve itemiçindeki öğelerden birine eşitse çalışmalıdır myList. Belki de öğelerden biriyle tam olarak eşleşmeyen bir dize bulmaya çalışıyorsunuz ya da yanlışlıktan muzdarip bir kayan nokta değeri kullanıyorsunuzdur.

İkinci sorunuza gelince: Listelerdeki şeyleri "bulmanın" birkaç yolu var.

İçeride bir şey olup olmadığını kontrol etme

Tanımladığınız kullanım durumu budur: Listenin içinde bir şey olup olmadığını kontrol etme. Bildiğiniz gibi, inbunun için operatörü kullanabilirsiniz :

3 in [1, 2, 3] # => True

Bir koleksiyona filtre uygulama

Yani, belirli bir koşulu karşılayan bir sırayla tüm öğeleri bulmak. Bunun için liste kavrama veya jeneratör ifadeleri kullanabilirsiniz:

matches = [x for x in lst if fulfills_some_condition(x)]
matches = (x for x in lst if x > 6)

İkincisi, sadece yinelediğiniz anda oluşturulacak bir tür tembel liste olarak hayal edebileceğiniz bir jeneratör döndürecektir . Bu arada, birincisi tam olarak

matches = filter(fulfills_some_condition, lst)

Burada üst düzey işlevleri iş başında görebilirsiniz. Python 3'te filterbir liste değil, jeneratör benzeri bir nesne döndürür.

İlk olayı bulma

Yalnızca bir koşulla eşleşen ilk şeyi istiyorsanız (ancak henüz ne olduğunu bilmiyorsanız), bir for döngüsü kullanmak (muhtemelen elseiyi bilinmeyen bir maddeyi de kullanmak) iyidir . Ayrıca kullanabilirsiniz

next(x for x in lst if ...)

ilk eşleşmeyi döndürür veya StopIterationbulunmazsa a değerini yükseltir . Alternatif olarak,

next((x for x in lst if ...), [default value])

Bir öğenin yerini bulma

Listelerde, belirli bir öğenin listede neredeindex olduğunu bilmek istiyorsanız bazen yararlı olabilecek bir yöntem de vardır :

[1,2,3].index(2) # => 1
[1,2,3].index(4) # => ValueError

Ancak, kopyalarınız varsa .indexher zaman en düşük dizini döndürdüğünü unutmayın : ......

[1,2,3,2].index(2) # => 1

Kopyalar varsa ve tüm dizinleri istiyorsanız, enumerate()bunun yerine kullanabilirsiniz :

[i for i,x in enumerate([1,2,3,2]) if x==2] # => [1, 3]

10
Stephane: Benim kez daha tekrarlamak isterim if x in listolduğu değil insanların yerleşik bir işlevi olmayan şikayetçi o şey. Belirli bir koşulla eşleşen bir listede bir şeyin ilk ortaya çıkışını bulmanın açık bir yolu olmadığından şikayet ediyorlar. Ama cevabımda belirtildiği gibi, next()(ab) bunun için kullanılabilir.
Niklas

3
@Stephane: İkincisi bir demet değil, bir jeneratör (temel olarak henüz oluşturulmamış bir liste). Sonucu yalnızca bir kez kullanmak istiyorsanız, genellikle bir jeneratör tercih edilir. Ancak, oluşturulan koleksiyonu daha sonra birkaç kez kullanmak istiyorsanız, ilk etapta açık bir liste oluşturmanız önerilir. Güncellememe bir göz atın, şimdi biraz daha iyi yapılandırılmış :)
Niklas B.

26
"İlk olayı bulma" örneğiniz altındır. [list comprehension...][0]Yaklaşımdan daha
pitonik

4
Ben daha fazla python 'fonksiyonel' yetenekleri ile dissiapointed duyuyorum. Haskell'de Data.List modülünde tam olarak bunu yapan find fonksiyonu vardır. Ama python'da değil ve bir kütüphane yapmak küçüktür, bu yüzden aynı mantığı tekrar tekrar uygulamak zorundasınız. Ne israf ...
user1685095

3
Bir kwarg olsa daha iyi olurdu index()denilen keygibi çalıştı keytarafından kabul max(); örneğin: index(list, key=is_prime).
Curt

189

Bir öğe bulmak veya Nonevarsayılanı kullanmak istiyorsanız, öğe listede bulunamazsa öğe nextyükseltilmez StopIteration:

first_or_default = next((x for x in lst if ...), None)

1
nextilk parametre olarak yineleyici alır ve list / tuple yineleyici DEĞİLDİR. Bu yüzden edilmelidir first_or_default = next(iter([x for x in lst if ...]), None)bkz docs.python.org/3/library/functions.html#next
Devy

7
@Devy: Doğru, ama (x for x in lst if ...)liste üzerinde bir jeneratör olup lst( olan bir yineleyici). Bunu yaparsanız next(iter([x for x in lst if ...]), None), [x for x in lst if ...]çok daha pahalı bir işlem olacak listeyi oluşturmanız gerekir.
Erlend Graff

1
Burada bir bulma fonksiyonu tanımlamak için bir soyutlama vardır. Sadece ifbir lambda içindeki boolean expession kapsüllemek ve find(fn,list)genellikle jeneratör kodu şaşırtmak yerine yazabilirsiniz .
semiomant

22

Niklas B.'nin cevabı oldukça kapsamlı olsa da, bir listede bir öğe bulmak istediğimizde dizinini almak bazen yararlı olabilir:

next((i for i, x in enumerate(lst) if [condition on x]), [default value])

11

İlk olayı bulma

Bunun için bir tarif var itertools:

def first_true(iterable, default=False, pred=None):
    """Returns the first true value in the iterable.

    If no true value is found, returns *default*

    If *pred* is not None, returns the first item
    for which pred(item) is true.

    """
    # first_true([a,b,c], x) --> a or b or c or x
    # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
    return next(filter(pred, iterable), default)

Örneğin, aşağıdaki kod listedeki ilk tek sayıyı bulur:

>>> first_true([2,3,4,5], None, lambda x: x%2==1)
3  

6

Başka bir alternatif: öğenin bir listede olup olmadığını kontrol edebilirsiniz if item in list:, ancak bu O (n) sırasıdır. Büyük öğe listeleriyle uğraşıyorsanız ve bilmeniz gereken tek şey, bir şeyin listenizin bir üyesi olup olmadığıysa, listeyi önce bir kümeye dönüştürebilir ve sabit zaman ayarı aramasından yararlanabilirsiniz :

my_set = set(my_list)
if item in my_set:  # much faster on average than using a list
    # do something

Her durumda doğru çözüm olmayacak, ancak bazı durumlarda bu size daha iyi performans verebilir.

Kümeyi ile oluşturmanın set(my_list)da O (n) olduğunu unutmayın, bu yüzden bunu sadece bir kez yapmanız gerekiyorsa, bunu bu şekilde yapmak daha hızlı değildir. Yine de üyeliği tekrar tekrar kontrol etmeniz gerekiyorsa, bu ilk set oluşturma işleminden sonraki her arama için O (1) olacaktır.


4

Dize listesiyle çalışırken iki olası aramadan birini kullanmak isteyebilirsiniz:

  1. liste öğesi bir öğeye eşitse ('örnek' ['bir', 'örnek', 'iki'] 'de):

    if item in your_list: some_function_on_true()

    'ex' in ['one', 'ex', 'two'] => Doğru

    'ex_1' ['one', 'ex', 'two'] => Yanlış

  2. liste öğesi bir öğeye benziyorsa ('ex' ['bir,' örnek ',' iki '] veya' example_1 '[' bir ',' örnek ',' iki ']' de ise):

    matches = [el for el in your_list if item in el]

    veya

    matches = [el for el in your_list if el in item]

    daha sonra len(matches)gerekirse kontrol edin veya okuyun.


3

Tanım ve Kullanım

count()yöntem belirtilen değere sahip eleman sayısını verir.

Sözdizimi

list.count(value)

misal:

fruits = ['apple', 'banana', 'cherry']

x = fruits.count("cherry")

Soru örneği:

item = someSortOfSelection()

if myList.count(item) >= 1 :

    doMySpecialFunction(item)

2
Bu çok uzun bir listede etkili mi? Milyonlarca liste söylesin mi?
3kstc

1
Emin değilim !!!
josef

1

list.index(x)Listede bulunursa x'in dizinini döndüren veya #ValueErrorx bulunmazsa bir ileti döndüren yerine kullanmak yerine, listedeki x list.count(x)oluşum sayısını döndüren (x'in gerçekten listede olduğunu doğrulama) veya bunu kullanabilirsiniz. aksi takdirde 0 değerini döndürür (x yokluğunda). En güzel şey count(), kodunuzu kırmaması veya x bulunmadığında bir istisna atmanızı gerektirmesidir


ve kötü olan şey unsurları sayması . Öğe bulunduğunda durmaz. performans büyük listelerde kötü
Jean-François Fabre

1

Eğer koleksiyonda değerin bir kez var olup olmadığını kontrol edecekseniz 'in' operatörünü kullanmak iyidir. Ancak, birden fazla kez kontrol edecekseniz, bisect modülünü kullanmanızı öneririm. İki modül modülünün kullanımının sıralanması gerektiğini unutmayın. Böylece verileri bir kez sıralarsınız ve sonra bisect kullanabilirsiniz. Makinemde bisect modülünü kullanmak 'in' operatörünü kullanmaktan yaklaşık 12 kat daha hızlıdır.

Python 3.8 ve üstü sözdizimini kullanan bir kod örneği:

import bisect
from timeit import timeit

def bisect_search(container, value):
    return (
      (index := bisect.bisect_left(container, value)) < len(container) 
      and container[index] == value
    )

data = list(range(1000))
# value to search
true_value = 666
false_value = 66666

# times to test
ttt = 1000

print(f"{bisect_search(data, true_value)=} {bisect_search(data, false_value)=}")

t1 = timeit(lambda: true_value in data, number=ttt)
t2 = timeit(lambda: bisect_search(data, true_value), number=ttt)

print("Performance:", f"{t1=:.4f}, {t2=:.4f}, diffs {t1/t2=:.2f}")

Çıktı:

bisect_search(data, true_value)=True bisect_search(data, false_value)=False
Performance: t1=0.0220, t2=0.0019, diffs t1/t2=11.71

0

Dizeler listesinin öğelerinde ek / istenmeyen beyaz alan olmadığından emin olun. Maddelerin açıklanmasına engel olabilecek bir sebep bu değil.

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.