Wie überprüfe ich, ob eines der folgenden Elemente in einer Liste enthalten ist?

220

Ich versuche einen kurzen Weg zu finden, um festzustellen, ob eines der folgenden Elemente in einer Liste enthalten ist, aber mein erster Versuch funktioniert nicht. Neben dem Schreiben einer Funktion, um dies zu erreichen, können Sie auf kurze Weise überprüfen, ob sich eines von mehreren Elementen in einer Liste befindet.

>>> a = [2,3,4]
>>> print (1 or 2) in a
False
>>> print (2 or 1) in a
True
Deon
quelle
Lustige Sache, ich habe überprüft, wie 'und' sich verhält. 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')ist wahr falsch falsch falsch wahr
Piotr Kamoda

Antworten:

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

Sowohl leere Listen als auch leere Mengen sind falsch, sodass Sie den Wert direkt als Wahrheitswert verwenden können.

Joe Koberg
quelle
6
Die Kreuzungsidee gab mir diese Idee. return len (set (a) .intersection (set (b)))
Deon
13
FWIW - Ich habe einen Geschwindigkeitsvergleich durchgeführt, und die allererste Lösung, die hier angeboten wurde, war bei weitem das Fasten.
Jackiekazil
2
@ user89788 Antwort mit einem Generator ist wieder viel schneller, weil anykann früh zurückkehren, sobald es einen TrueWert findet - es muss nicht die ganze Liste zuerst
erstellen
Die zweite / sets-Lösung funktioniert nicht, wenn Sie Duplikate in der Liste haben (da Sets nur eines von jedem Element enthalten). Wenn "L1 = [1,1,2,3]" und "L2 = [1,2,3]", werden sich alle Elemente schneiden.
Donrondadon
Ich weiß, dass dies fast 10 Jahre alt ist, aber die erste Lösung scheint für mich nicht zu funktionieren. Ich habe die Zahlen in L2 durch Zeichenfolgen ersetzt, und es wird der folgende Fehler angezeigt: TypeError: 'in <Zeichenfolge>' erfordert Zeichenfolge als linken Operanden, nicht Liste
Roastbeeef
227

Ah, Tobias, du hast mich geschlagen. Ich habe an diese geringfügige Abweichung von Ihrer Lösung gedacht:

>>> a = [1,2,3,4]
>>> b = [2,7]
>>> print(any(x in a for x in b))
True
ojdo
quelle
5
Mir ist klar, dass dies eine sehr alte Antwort ist, aber wenn eine Liste sehr lang und die andere kurz ist, gibt es eine Reihenfolge, die zu einer schnelleren Leistung führen würde? (dh x in long for x in shortvs x in short for x in long)
Luke Sapan
11
@ LukeSapan: Du bist richtig. Diese Reihenfolge erhalten Sie über "print any (x in max (a, b, key = len) für x in min (a, b, key = len))". Dies verwendet x in long für x in short.
Nuclearman
2
Dies ist die beste Antwort, da sie einen Generator verwendet und zurückkehrt, sobald eine Übereinstimmung gefunden wird (wie andere gesagt haben, nur nicht auf diese Antwort!).
Dotcomly
4
@Nuclearman, aufgepasst: Wenn die beiden Listen aund bdie gleiche Länge, max und min wird die am weitesten links Liste zurück, die das macht any()Anruf auf beiden Seiten arbeitet über die gleiche Liste. Wenn Sie unbedingt die Länge überprüfen müssen, kehren Sie die Reihenfolge der Listen im zweiten Aufruf um : any(x in max(a, b, key=len) for x in (b, a, key=len)).
Noah Bogart
3
@NoahBogart Sie sind richtig und diese Lösung scheint so gut wie jede andere. Ich nehme auch an, Sie meinten: any(x in max(a, b, key=len) for x in min(b, a, key=len))(verpasste die min).
Nuclearman
29

Vielleicht etwas fauler:

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

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

quelle
1
Es ist fast das gleiche wie das, das ich gepostet habe.
Bastien Léonard
5
@ BastienLéonard ... außer es ist viel schneller, weil es einen Generator verwendet und daher anyfrüh zurückkehren kann, während Ihre Version die gesamte Liste aus dem Verständnis erstellen muss, bevor anysie verwendet werden kann. @ user89788 Antwort ist etwas besser, weil die doppelten Klammern unnötig sind
Anentropic
17

Überlegen Sie, was der Code tatsächlich sagt!

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

Das sollte es wahrscheinlich erklären. :) Python implementiert anscheinend "faul oder", was keine Überraschung sein sollte. Es führt es ungefähr so ​​aus:

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

Im ersten Beispiel x == 1und y == 2. Im zweiten Beispiel ist es umgekehrt. Aus diesem Grund werden je nach Reihenfolge unterschiedliche Werte zurückgegeben.

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

Code Golf Version. Erwägen Sie die Verwendung eines Sets, wenn dies sinnvoll ist. Ich finde das lesbarer als ein Listenverständnis.

00500005
quelle
12

1 Zeile ohne Listenverständnis.

>>> 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
Himel Das
quelle
7

Das Beste, was ich mir vorstellen konnte:

any([True for e in (1, 2) if e in a])
Bastien Léonard
quelle
6

In Python 3 können wir das Entpack-Sternchen verwenden. Gegeben zwei Listen:

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

Bearbeiten: Alkanens Vorschlag einbeziehen

Daniel Braun
quelle
1
@Anthony erstellt eine Menge, die die Elemente in a enthält, und eine andere Menge, die die Elemente in b enthält. Dann findet es den Schnittpunkt (gemeinsam genutzte Elemente) zwischen diesen Mengen und any () gibt true zurück, wenn es solche Elemente gibt, die wahr sind. Die Lösung funktioniert nicht, wenn die einzigen gemeinsam genutzten Elemente falsch sind (z. B. die Nummer 0). Es könnte besser sein, len () als any () zu verwenden
alkanen
1
@alkanen Guter Anruf
Daniel Braun
Warum nicht die Set-Funktion verwenden?
Alex78191
5

Wenn Sie denken "prüfen, ob a in b ist", denken Sie an Hashes (in diesem Fall setzt). Der schnellste Weg besteht darin, die Liste, die Sie überprüfen möchten, zu hashen und dann jedes Element dort zu überprüfen.

Aus diesem Grund antwortet Joe Koberg schnell: Die Überprüfung der eingestellten Kreuzung ist sehr schnell.

Wenn Sie jedoch nicht viele Daten haben, kann das Erstellen von Sets Zeitverschwendung sein. Sie können also einen Satz der Liste erstellen und einfach jedes Element überprüfen:

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

Wenn die Anzahl der zu überprüfenden Elemente gering ist, kann der Unterschied vernachlässigbar sein. Aber überprüfen Sie viele Zahlen anhand einer großen Liste ...

Tests:

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)

Geschwindigkeiten:

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

Die Methode, die durchweg schnell ist, besteht darin, einen Satz (aus der Liste) zu erstellen, aber der Schnittpunkt funktioniert bei großen Datenmengen am besten!

Dantiston
quelle
3

In einigen Fällen (z. B. eindeutige Listenelemente) können Set-Operationen verwendet werden.

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

Oder verwenden Sie set.isdisjoint () ,

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

Dies wird es in einer Zeile tun.

>>> a=[2,3,4]
>>> b=[1,2]
>>> bool(sum(map(lambda x: x in b, a)))
True
Chris Upchurch
quelle
Ich bekomme hier kein Wahr >>> drucke a [2, 3, 4] >>> drucke b [2, 7] >>> reduziere (Lambda x, y: x in b, a) Falsch
Deon
Ja. Du hast recht. reduct () handhabte boolesche Werte nicht so, wie ich es mir vorgestellt hatte. Die überarbeitete Version, die ich oben geschrieben habe, funktioniert jedoch für diesen Fall.
Chris Upchurch
2

Ich habe einige der in anderen Antworten und Kommentaren genannten Lösungen gesammelt und dann einen Geschwindigkeitstest durchgeführt. not set(a).isdisjoint(b)Es stellte sich heraus, dass es das schnellste war, es verlangsamte sich auch nicht viel, als das Ergebnis war False.

Jeder der drei Läufe testet eine kleine Auswahl der möglichen Konfigurationen von aund b. Die Zeiten sind in Mikrosekunden angegeben.

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
Socken kauen
quelle
0

Ich muss sagen, dass meine Situation möglicherweise nicht das ist, wonach Sie suchen, aber sie bietet möglicherweise eine Alternative zu Ihrem Denken.

Ich habe sowohl die set () - als auch eine beliebige () Methode ausprobiert, habe aber immer noch Probleme mit der Geschwindigkeit. Also erinnerte ich mich, dass Raymond Hettinger sagte, alles in Python sei ein Wörterbuch und benutze Dikt, wann immer du kannst. Das habe ich versucht.

Ich habe ein defaultdict mit int verwendet, um negative Ergebnisse anzuzeigen, und das Element in der ersten Liste als Schlüssel für die zweite Liste verwendet (konvertiert in defaultdict). Da Sie mit dict sofort nachschlagen können, wissen Sie sofort, ob dieses Element im defaultdict vorhanden ist. Ich weiß, dass Sie die Datenstruktur für Ihre zweite Liste nicht immer ändern können, aber wenn Sie dies von Anfang an können, ist es viel schneller. Möglicherweise müssen Sie list2 (größere Liste) in ein Standarddikt konvertieren, wobei key der potenzielle Wert ist, den Sie anhand einer kleinen Liste überprüfen möchten, und der Wert entweder 1 (Treffer) oder 0 (kein Treffer, Standard) ist.

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
yangliu2
quelle
-4

Einfach.

_new_list = []
for item in a:
    if item in b:
        _new_list.append(item)
    else:
        pass
PyGuy
quelle
1
Dies beantwortet die Frage nicht. OP möchte wissen, ob ein Wert aus der Liste a in der Liste enthalten ist b.
That1Guy