Aşağıdaki öğelerden birinin listede olup olmadığını nasıl kontrol edebilirim?


220

Aşağıdaki öğelerden herhangi birinin bir listede olup olmadığını görmek için kısa bir yol bulmaya çalışıyorum, ancak ilk denemem çalışmıyor. Bunu gerçekleştirmek için bir işlev yazmanın yanı sıra, birden fazla öğeden birinin listede olup olmadığını kontrol etmenin herhangi bir kısa yolu.

>>> a = [2,3,4]
>>> print (1 or 2) in a
False
>>> print (2 or 1) in a
True

Komik bir şey, 've' nasıl davrandığını kontrol ettim. a = [1, 2] b = [3, 5, 2, 6, 8, 9] c = [3, 5, 6, 8, 1, 9] print( (1 and 2) in b ,(2 and 1) in b ,(1 and 2) in c ,(2 and 1) in c, sep='\n')Yanlış Yanlış Doğru
Piotr Kamoda 02

Yanıtlar:


266
>>> L1 = [2,3,4]
>>> L2 = [1,2]
>>> [i for i in L1 if i in L2]
[2]


>>> S1 = set(L1)
>>> S2 = set(L2)
>>> S1.intersection(S2)
set([2])

Hem boş listeler hem de boş kümeler Yanlış'tır, bu nedenle değeri doğrudan doğru değeri olarak kullanabilirsiniz.


6
Kavşak fikri bana bu fikri verdi. dönüş len (set (a). kavşak (set (b)))
Deon

14
FWIW - Bir hız karşılaştırması yaptım ve burada sunulan ilk çözüm açık ara oldu.
jackiekazil

2
@ user89788'in bir jeneratör kullanma cevabı çok daha hızlıdır, çünkü anybir Truedeğer bulur bulmaz erken dönebilir - önce tüm listeyi oluşturmak zorunda değildir
Anentropic

Listede yinelemeler varsa ikinci / set çözümü çalışmaz (setler her öğeden yalnızca birini içerdiğinden). `L1 = [1,1,2,3] 've' L2 = [1,2,3] 'ise, tüm öğelerin kesiştiği görülür.
donrondadon

bunun neredeyse 10 yaşında olduğunu biliyorum, ama ilk çözüm benim için çalışmıyor gibi görünüyor. dizeleri için L2 sayıları yerine, ve aşağıdaki hatayı alıyorum: TypeError: 'in <string>' sol işlenen, liste değil olarak dize gerektirir
roastbeeef

227

Ah, Tobias beni dövüyorsun. Çözümünüzdeki bu küçük varyasyonu düşünüyordum:

>>> a = [1,2,3,4]
>>> b = [2,7]
>>> print(any(x in a for x in b))
True

5
Bunun çok eski bir cevap olduğunu anlıyorum, ancak bir liste çok uzun ve diğeri kısa ise, daha hızlı performans sağlayacak bir emir var mı? (yani, x in long for x in shortvs x in short for x in long)
Luke Sapan

11
@ LukeSapan: Haklısın. Bu düzen, "herhangi birinden (maksimum x (x, a, b, anahtar = len) x, dakika (a, b, anahtar = len)) yazdır" yoluyla elde edilebilir. Bu kısaca x için uzun, x kullanır.
Nuclearman

2
Bu en iyi cevaptır, çünkü bir jeneratör kullanır ve bir maç bulunur bulunmaz geri döner (diğerleri söylediği gibi, bu cevapta değil!).
dotcomly

4
@Nuclearman, dikkat edin: İki liste ave baynı uzunluktaysa, max ve min en soldaki listeyi döndürür, bu da any()çağrıyı her iki tarafta da aynı liste üzerinden yapar . Kesinlikle uzunluğu kontrol gerektiriyorsa, ikinci çağrı listelerinin sırasını tersine çevirmek: any(x in max(a, b, key=len) for x in (b, a, key=len)).
Noah Bogart

3
@NoahBogart Haklısınız ve bu çözüm herhangi bir şey kadar iyi görünüyor. Ben de demek istediğini sanıyorum: any(x in max(a, b, key=len) for x in min(b, a, key=len))(min özledim).
Nükleer Adam

29

Belki biraz daha tembel:

a = [1,2,3,4]
b = [2,7]

print any((True for x in a if x in b))

1
Yayınladığımla neredeyse aynı.
Bastien Léonard

5
@ BastienLéonard ... çok daha hızlı, çünkü bir jeneratör kullanıyor ve böylece anyerken dönebiliyor any. @ user89788'in cevabı biraz daha iyidir çünkü çift parantezler gereksizdir
Anentropic

17

Kodun gerçekte ne dediğini düşünün!

>>> (1 or 2)
1
>>> (2 or 1)
2

Muhtemelen açıklamalı. :) Python görünüşe göre sürpriz olmamalı "tembel veya", uygular. Bunun gibi bir şey yapar:

def or(x, y):
    if x: return x
    if y: return y
    return False

İlk örnekte, x == 1 ve y == 2. İkinci örnekte, bunun tersi de geçerlidir. Bu yüzden sıralarına bağlı olarak farklı değerler döndürür.


16
a = {2,3,4}
if {1,2} & a:
    pass

Kod golf versiyonu. Eğer mantıklı geliyorsa bir set kullanmayı düşünün. Bunu bir liste kavrayışından daha okunabilir buluyorum.


12

Liste kavrama olmadan 1 satır.

>>> any(map(lambda each: each in [2,3,4], [1,2]))
True
>>> any(map(lambda each: each in [2,3,4], [1,5]))
False
>>> any(map(lambda each: each in [2,3,4], [2,4]))
True


6

Python 3'te, açma yıldız işaretini kullanmaya başlayabiliriz. Verilen iki liste:

bool(len({*a} & {*b}))

Edit: alkanen'in önerisini dahil et


1
@Anthony, a öğesindeki öğeleri içeren bir küme ve b öğesindeki öğeleri içeren başka bir küme oluşturur, ardından bu kümeler arasındaki kesişmeyi (paylaşılan öğeler) bulur ve doğrulukta olan bu tür öğeler varsa any () işlevi true değerini döndürür. Paylaşılan tek eleman (lar) yanlışsa (0 sayısı gibi) çözüm çalışmaz.
Len

1
@alkanen İyi çağrı
Daniel Braun

neden set fonksiyonunu kullanmıyorsunuz?
Alex78191

5

"A b olup olmadığını kontrol edin" diye düşündüğünüzde karmaları düşünün (bu durumda kümeler). En hızlı yol, kontrol etmek istediğiniz listeyi hash etmek ve ardından oradaki her öğeyi kontrol etmektir.

Bu yüzden Joe Koberg'in cevabı hızlı: ayarlı kavşağı kontrol etmek çok hızlı.

Yine de çok fazla veriye sahip değilseniz, set yapmak zaman kaybı olabilir. Böylece, bir liste oluşturabilir ve her bir öğeyi kontrol edebilirsiniz:

tocheck = [1,2] # items to check
a = [2,3,4] # the list

a = set(a) # convert to set (O(len(a)))
print [i for i in tocheck if i in a] # check items (O(len(tocheck)))

Kontrol etmek istediğiniz öğe sayısı az olduğunda, fark göz ardı edilebilir. Ancak büyük bir listeye göre çok sayıda sayıyı kontrol edin ...

testler:

from timeit import timeit

methods = ['''tocheck = [1,2] # items to check
a = [2,3,4] # the list
a = set(a) # convert to set (O(n))
[i for i in tocheck if i in a] # check items (O(m))''',

'''L1 = [2,3,4]
L2 = [1,2]
[i for i in L1 if i in L2]''',

'''S1 = set([2,3,4])
S2 = set([1,2])
S1.intersection(S2)''',

'''a = [1,2]
b = [2,3,4]
any(x in a for x in b)''']

for method in methods:
    print timeit(method, number=10000)

print

methods = ['''tocheck = range(200,300) # items to check
a = range(2, 10000) # the list
a = set(a) # convert to set (O(n))
[i for i in tocheck if i in a] # check items (O(m))''',

'''L1 = range(2, 10000)
L2 = range(200,300)
[i for i in L1 if i in L2]''',

'''S1 = set(range(2, 10000))
S2 = set(range(200,300))
S1.intersection(S2)''',

'''a = range(200,300)
b = range(2, 10000)
any(x in a for x in b)''']

for method in methods:
    print timeit(method, number=1000)

hızlar:

M1: 0.0170331001282 # make one set
M2: 0.0164539813995 # list comprehension
M3: 0.0286040306091 # set intersection
M4: 0.0305438041687 # any

M1: 0.49850320816 # make one set
M2: 25.2735087872 # list comprehension
M3: 0.466138124466 # set intersection
M4: 0.668627977371 # any

Tutarlı bir şekilde hızlı olan yöntem bir set (listeden) yapmaktır, ancak kesişim büyük veri setlerinde en iyisidir!


3

Bazı durumlarda (örn. Benzersiz liste öğeleri), ayar işlemleri kullanılabilir.

>>> a=[2,3,4]
>>> set(a) - set([2,3]) != set(a)
True
>>> 

Veya set.isdisjoint () kullanarak ,

>>> not set(a).isdisjoint(set([2,3]))
True
>>> not set(a).isdisjoint(set([5,6]))
False
>>> 

2

Bu bir satırda yapacak.

>>> a=[2,3,4]
>>> b=[1,2]
>>> bool(sum(map(lambda x: x in b, a)))
True

Burada bir True almıyorum >>> bir [2, 3, 4] yazdırın >>> print b [2, 7] >>> azaltın (lambda x, y: x in b, a) Yanlış
Deon

Evet. Haklısın. reduce (), boole değerlerini düşündüğüm gibi kullanmıyordu. Yukarıda yazdığım gözden geçirilmiş versiyon bu durumda işe yarıyor.
Chris Upchurch

2

Diğer cevaplarda ve yorumlarda bahsedilen çözümlerin birçoğunu topladım, sonra bir hız testi yaptım. not set(a).isdisjoint(b)en hızlı olduğu ortaya çıktı, sonuç olduğunda da çok yavaşlamadı False.

Üç işlem her muhtemel konfigürasyonları küçük bir örnek test ave b. Zamanlar mikrosaniye cinsindendir.

Any with generator and max
        2.093 1.997 7.879
Any with generator
        0.907 0.692 2.337
Any with list
        1.294 1.452 2.137
True in list
        1.219 1.348 2.148
Set with &
        1.364 1.749 1.412
Set intersection explcit set(b)
        1.424 1.787 1.517
Set intersection implicit set(b)
        0.964 1.298 0.976
Set isdisjoint explicit set(b)
        1.062 1.094 1.241
Set isdisjoint implicit set(b)
        0.622 0.621 0.753

import timeit

def printtimes(t):
    print '{:.3f}'.format(t/10.0),

setup1 = 'a = range(10); b = range(9,15)'
setup2 = 'a = range(10); b = range(10)'
setup3 = 'a = range(10); b = range(10,20)'

print 'Any with generator and max\n\t',
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup3).timeit(10000000))
print

print 'Any with generator\n\t',
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup3).timeit(10000000))
print

print 'Any with list\n\t',
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup3).timeit(10000000))
print

print 'True in list\n\t',
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup3).timeit(10000000))
print

print 'Set with &\n\t',
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup3).timeit(10000000))
print

print 'Set intersection explcit set(b)\n\t',
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup3).timeit(10000000))
print

print 'Set intersection implicit set(b)\n\t',
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup3).timeit(10000000))
print

print 'Set isdisjoint explicit set(b)\n\t',
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup3).timeit(10000000))
print

print 'Set isdisjoint implicit set(b)\n\t',
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup3).timeit(10000000))
print

0

Durumumun aradığınız şey olmadığını söylemeliyim, ama bu sizin düşüncenize bir alternatif sağlayabilir.

Ben set () ve herhangi bir () yöntemini denedim ama yine de hız sorunları var. Raymond Hettinger'in python'daki her şeyin bir sözlük olduğunu ve mümkün olduğunda dict kullandığını söylediğini hatırladım. Ben de öyle denedim.

Negatif sonuçları belirtmek için int ile bir defaultdict kullandım ve ilk listedeki öğeyi ikinci listenin anahtarı olarak kullandım (defaultdict'a dönüştürüldü). Dict ile anında arama yaptığınızdan, bu öğenin defaultdict içinde olup olmadığını hemen bilirsiniz. İkinci listeniz için veri yapısını her zaman değiştiremeyeceğinizi biliyorum, ancak en başından beri yapabiliyorsanız, çok daha hızlı. List2'yi (daha büyük liste) varsayılan bir diske dönüştürmeniz gerekebilir; burada anahtar, küçük listeden kontrol etmek istediğiniz potansiyel değerdir ve değer 1 (isabet) veya 0'dır (isabet yok, varsayılan).

from collections import defaultdict
already_indexed = defaultdict(int)

def check_exist(small_list, default_list):
    for item in small_list:
        if default_list[item] == 1:
            return True
    return False

if check_exist(small_list, already_indexed):
    continue
else:
    for x in small_list:
        already_indexed[x] = 1

-4

Basit.

_new_list = []
for item in a:
    if item in b:
        _new_list.append(item)
    else:
        pass

1
Bu soruya cevap vermiyor. OP listede herhangi bir değerin listede a olup olmadığını bilmek istiyor b.
That1Guy
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.