2009-04-11 8 views
144

Sto provando a trovare un modo breve per vedere se uno qualsiasi dei seguenti elementi è in una lista, ma il mio primo tentativo non funziona. Oltre a scrivere una funzione per realizzare questo, è il modo più breve per verificare se uno di più elementi è in una lista.Come verificare se uno dei seguenti elementi è in un elenco?

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

La cosa divertente, ho controllato come 'e' si comporta. 'a = [1, 2] b = [3, 5, 2, 6, 8, 9] c = [3, 5, 6, 8, 1, 9] stampa ( (1 e 2) in b , (2 e 1) in b , (1 e 2) in c , (2 e 1) in C, settembre = '\ n') 'è vero Falso false True –

+0

[Puoi controllare qui, potrebbe aiutarti] (http://stackoverflow.com/questions/3389574/check-if-multiple-strings-exist-in-another-string/40880830#40880830) –

risposta

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

Sia le liste vuote che le serie vuote sono false, quindi è possibile utilizzare il valore direttamente come valore di verità.

+3

L'intersezione l'idea mi ha dato questa idea. return len (set (a) .intersection (set (b))) – Deon

+8

FWIW - Ho fatto un confronto di velocità, e la prima soluzione offerta qui era il digiuno di gran lunga. – jackiekazil

+0

La risposta di @ user89788 usando un generatore è di nuovo molto più veloce, perché 'any' può tornare presto non appena trova un valore' True' - non deve prima costruire l'intero elenco – Anentropic

16

Pensa a ciò che dice effettivamente il codice!

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

Questo dovrebbe probabilmente spiegarlo. :) Python apparentemente implementa "pigro o", che non dovrebbe sorprendere. Si compie qualcosa di simile:

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

Nel primo esempio, x == 1 e y == 2. Nel secondo esempio, è viceversa. Ecco perché restituisce valori diversi a seconda dell'ordine.

4

meglio che ho potuto venire con:

any([True for e in (1, 2) if e in a]) 
1

Questo lo farà in una sola riga.

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

non ricevo un vero qui >>> stampare un [2, 3, 4] >>> print b [2, 7] >>> ridurre (lambda x, y: x in B , a) False – Deon

+0

Sì. Hai ragione. reduce() non stava abbastanza gestendo i valori booleani come pensavo. La versione rivista che ho scritto sopra funziona comunque per quel caso. –

4

In alcuni casi (ad esempio, elementi di elenco univoci), è possibile utilizzare le operazioni di impostazione.

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

Oppure, utilizzando set.isdisjoint(),

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

Forse un po 'più pigri:

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

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

È quasi uguale a quello che ho postato. –

+4

@ BastienLéonard ... eccetto che è molto più veloce perché usa un generatore e quindi 'any' può tornare presto, mentre la tua versione deve costruire l'intera lista dalla comprensione prima che 'any' possa usarla. La risposta di @ user89788 è leggermente migliore perché le doppie parentesi non sono necessarie – Anentropic

+0

IMO, questa dovrebbe essere la migliore risposta –

143

Ah, Tobias mi ha battuto ad esso. Stavo pensando di questa leggera variazione sul tuo soluzione:

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

Mi rendo conto che questa è una risposta molto vecchia, ma se una lista è molto lunga e l'altra è breve, c'è un ordine che sarebbe cedere prestazioni più veloci? (ad esempio, 'x in long per x in short' vs' x in breve per x in long') –

+8

@LukeSapan: sei corretto. Tale ordine può essere ottenuto tramite "stampa qualsiasi (x in max (a, b, key = len) per x in min (a, b, key = len))". Questo utilizza x in long per x in breve. – Nuclearman

+0

Questa è la migliore risposta perché usa un generatore e ritornerà non appena viene trovata una corrispondenza (come altri hanno detto, non solo su questa risposta!). – dotcomly

0
print (1 in a) or (2 in a) 

print (2 in a) or (5 in a) 

Questa è una domanda molto vecchio, ma non ero felice con una qualsiasi delle risposte, quindi ho dovuto aggiungere questo per amor di posteri.

4

Quando si pensa "check per vedere se un in B", pensano gli hash (in questo caso, set). Il modo più veloce consiste nel cancellare l'elenco che si desidera controllare, quindi controllare ciascun elemento in esso.

Questo è il motivo per la risposta di Joe Koberg è veloce: il controllo impostare incrocio è molto veloce.

Quando non si dispone di un sacco di dati, però, rendendo set può essere una perdita di tempo. Quindi, è possibile effettuare una serie di lista e basta controllare ogni voce:

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

Quando il numero di elementi che si desidera controllare è piccolo, la differenza può essere trascurabile. Ma controlla un sacco di numeri contro una grande lista ...

prove:

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) 

velocità:

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 

Il metodo che è costantemente veloce è quello di rendere un insieme (della lista), ma l'incrocio lavora su grandi insiemi di dati il ​​migliore!

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

Versione golf da golf. Considera di utilizzare un set se ha senso farlo. Trovo questo più leggibile di una lista di comprensione.

+2

Per me, questa è di gran lunga la soluzione più leggibile. Bello! –

7

1 riga senza comprensioni di elenchi.

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

Semplice.

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

Questo non risponde alla domanda. OP vuole sapere se * qualsiasi valore dalla lista * 'a' è nella lista' b'. – That1Guy

Problemi correlati