Wie kann ich zwei Listen in Python vergleichen und Übereinstimmungen zurückgeben?

380

Ich möchte zwei Listen nehmen und die Werte finden, die in beiden erscheinen.

a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]

returnMatches(a, b)

würde [5]zum Beispiel zurückkehren.

tehryan
quelle
4
Die Antworten unten scheinen mir alle falsch zu sein. Was passiert, wenn eine Zahl in einer der beiden Listen wiederholt wird? Sicher möchten Sie wissen, dass (?) (Z. B. sagen beide Listen zweimal '5'). Jede Lösung, die Sätze verwendet, entfernt sofort alle wiederholten Elemente und Sie verlieren diese Info.
MH
Mögliches Duplikat von Wie finde ich eine Listenkreuzung?
Kushan Gunasekera

Antworten:

486

Nicht der effizienteste, aber bei weitem der naheliegendste Weg, dies zu tun, ist:

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a) & set(b)
{5}

Wenn die Reihenfolge von Bedeutung ist, können Sie dies mit Listenverständnis wie folgt tun:

>>> [i for i, j in zip(a, b) if i == j]
[5]

(funktioniert nur für gleich große Listen, was die Reihenfolge der Bedeutung impliziert).

SilentGhost
quelle
15
Achtung, das Listenverständnis ist nicht unbedingt die schnellere Option. Bei größeren Sätzen (bei denen die Leistung am wahrscheinlichsten von Bedeutung ist) ist der bitweise Vergleich ( &) oder set(a).intersection(b)genauso schnell oder schneller als das Listenverständnis.
Joshmaker
24
Noch ein Hinweis zur Vorsicht: Das Listenverständnis findet die Werte, die in beiden an den gleichen Positionen erscheinen (dies ist, was SilentGhost mit "Reihenfolge ist signifikant" meinte). Die festgelegten Schnittlösungen finden auch Übereinstimmungen an VERSCHIEDENEN Positionen. Dies sind Antworten auf 2 ganz unterschiedliche Fragen ... (die Frage der
Operation
Wie machen Sie das, wenn Ihre Listen Listen von Listen sind, dh a = [[0,0], [1,0]] und b = [[2,3], [0,0]]
Schneems
3
Was wäre die zeitliche Komplexität des ersten Beispiels set(a) & set(b)?
AdjunctProfessorFalcon
Beachten Sie, dass dies nicht funktioniert, wenn beide Sätze leer sind und Sie erwarten, dass der Vergleich erfolgreich ist. Wechseln Sie also zu "(Satz (a) und Satz (b)) oder (nicht a und nicht b)"
Neil McGill
395

Verwenden Sie set.intersection () , es ist schnell und lesbar.

>>> set(a).intersection(b)
set([5])
Dennis
quelle
28
Diese Antwort weist eine gute algorithmische Leistung auf, da nur eine der Listen (kürzer sollte bevorzugt werden) zur schnellen Suche in eine Gruppe umgewandelt wird und die andere Liste durchlaufen wird, um ihre Elemente in der Gruppe nachzuschlagen.
u0b34a0f6ae
18
bool(set(a).intersection(b))für TrueoderFalse
Akshay
6
Diese Antwort ist flexibler und lesbarer, da die Benutzer möglicherweise differenceoder benötigen union.
Shihe Zhang
Was ist, wenn ich Objekte als Listenelemente habe und nur teilweise Übereinstimmungen möchte, dh nur einige Attribute müssen übereinstimmen, damit sie als übereinstimmendes Objekt betrachtet werden?
CGFoX
Gibt es einen Leistungsunterschied für .intersection()vs &?
Brandonbanks
106

Ein schneller Leistungstest, der die Lösung von Lutz zeigt, ist das Beste:

import time

def speed_test(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        for x in xrange(5000):
            results = func(*args, **kwargs)
        t2 = time.time()
        print '%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0)
        return results
    return wrapper

@speed_test
def compare_bitwise(x, y):
    set_x = frozenset(x)
    set_y = frozenset(y)
    return set_x & set_y

@speed_test
def compare_listcomp(x, y):
    return [i for i, j in zip(x, y) if i == j]

@speed_test
def compare_intersect(x, y):
    return frozenset(x).intersection(y)

# Comparing short lists
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]
compare_bitwise(a, b)
compare_listcomp(a, b)
compare_intersect(a, b)

# Comparing longer lists
import random
a = random.sample(xrange(100000), 10000)
b = random.sample(xrange(100000), 10000)
compare_bitwise(a, b)
compare_listcomp(a, b)
compare_intersect(a, b)

Dies sind die Ergebnisse auf meinem Computer:

# Short list:
compare_bitwise took 10.145 ms
compare_listcomp took 11.157 ms
compare_intersect took 7.461 ms

# Long list:
compare_bitwise took 11203.709 ms
compare_listcomp took 17361.736 ms
compare_intersect took 6833.768 ms

Natürlich sollte jeder künstliche Leistungstest mit einem Körnchen Salz durchgeführt werden. Da die set().intersection()Antwort jedoch mindestens so schnell wie die anderen Lösungen und auch am besten lesbar ist, sollte sie die Standardlösung für dieses häufig auftretende Problem sein.

Joshmaker
quelle
Set entfernt tatsächlich Wiederholungen, also funktioniert es in meinem Fall nicht
rgralma
@rgralma, das setaus einem vorhandenen ein neues macht, listentfernt nichts aus dem Original list. Wenn Sie möchten, dass eine spezielle Logik Duplikate in einer Liste behandelt, müssen Sie meiner Meinung nach eine neue Frage stellen, da die Antwort spezifisch sein muss, wie Duplikate behandelt werden sollen.
Joshmaker
67

Ich bevorzuge die satzbasierten Antworten, aber hier ist eine, die trotzdem funktioniert

[x for x in a if x in b]
SingleNegationElimination
quelle
15

Der einfachste Weg, dies zu tun, ist die Verwendung von Sets :

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a) & set(b)
set([5])
Greg Hewgill
quelle
15

Schneller Weg:

list(set(a).intersection(set(b)))
DisplacedAussie
quelle
14
>>> s = ['a','b','c']   
>>> f = ['a','b','d','c']  
>>> ss= set(s)  
>>> fs =set(f)  
>>> print ss.intersection(fs)   
   **set(['a', 'c', 'b'])**  
>>> print ss.union(fs)        
   **set(['a', 'c', 'b', 'd'])**  
>>> print ss.union(fs)  - ss.intersection(fs)   
   **set(['d'])**
setz
quelle
1
Die akzeptierte Antwort funktioniert nicht für Listen, die Zeichenfolgen enthalten. Dieser tut es.
Antony
12

Sie können dies auch versuchen, indem Sie gemeinsame Elemente in einer neuen Liste behalten.

new_list = []
for element in a:
    if element in b:
        new_list.append(element)
Mushfiq
quelle
5

Möchten Sie Duplikate? Wenn nicht, sollten Sie stattdessen Sets verwenden:


>>> set([1, 2, 3, 4, 5]).intersection(set([9, 8, 7, 6, 5]))
set([5])
Timothy Pratley
quelle
Wenn Sie wirklich Listen möchten, überschneiden sich java2s.com/Code/Python/List/Functiontointersecttwolists.htm >>> ([1, 2, 3, 4, 5], [9, 8, 7, 6, 5]) [5 ]
Timothy Pratley
Laut doc - ... sind fehleranfällige Konstruktionen wie Set ('abc') & 'cbs' zugunsten des besser lesbaren Set ('abc'). Intersection ('cbs') ausgeschlossen. - docs.python.org/library/sets.html
Aaron Newton
5

Eine andere, etwas funktionalere Möglichkeit, die Listengleichheit für Liste 1 (lst1) und Liste 2 (lst2) zu überprüfen, wenn Objekte die Tiefe eins haben und die Reihenfolge beibehalten wird, ist:

all(i == j for i, j in zip(lst1, lst2))   
es ist wichtig
quelle
4
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]

lista =set(a)
listb =set(b)   
print listb.intersection(lista)   
returnMatches = set(['5']) #output 

print " ".join(str(return) for return in returnMatches ) # remove the set()   

 5        #final output 
Harish Verma
quelle
Während dieser Code die Frage möglicherweise beantwortet, würde die Bereitstellung eines zusätzlichen Kontexts darüber, wie und / oder warum das Problem gelöst wird, den langfristigen Wert der Antwort verbessern.
Donald Duck
4

Kann auch itertools.product verwenden.

>>> common_elements=[]
>>> for i in list(itertools.product(a,b)):
...     if i[0] == i[1]:
...         common_elements.append(i[0])
SuperNova
quelle
3

Sie können verwenden

def returnMatches(a,b):
       return list(set(a) & set(b))
Prabhu
quelle
3

Sie können verwenden:

a = [1, 3, 4, 5, 9, 6, 7, 8]
b = [1, 7, 0, 9]
same_values = set(a) & set(b)
print same_values

Ausgabe:

set([1, 7, 9])
Adnan Ghaffar
quelle
4
Wie unterscheidet sich das von der akzeptierten Antwort von vor mehr als 6 Jahren?
tmdavison
1
Nun, ich schrieb das komplette Detail mit Ausgabe und gut für Anfänger Python
Adnan Ghaffar
2

Wenn Sie einen booleschen Wert wünschen:

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(b) == set(a)  & set(b) and set(a) == set(a) & set(b)
False
>>> a = [3,1,2]
>>> b = [1,2,3]
>>> set(b) == set(a)  & set(b) and set(a) == set(a) & set(b)
True
Matheus Araujo
quelle
1

Die folgende Lösung funktioniert für jede Reihenfolge von Listenelementen und unterstützt auch, dass beide Listen unterschiedlich lang sind.

import numpy as np
def getMatches(a, b):
    matches = []
    unique_a = np.unique(a)
    unique_b = np.unique(b)
    for a in unique_a:
        for b in unique_b:
            if a == b:
                matches.append(a)
    return matches
print(getMatches([1, 2, 3, 4, 5], [9, 8, 7, 6, 5, 9])) # displays [5]
print(getMatches([1, 2, 3], [3, 4, 5, 1])) # displays [1, 3]
Hafizur Rahman
quelle
1
Numpy hat eine spezielle Funktion dafür:np.intersect1d(list1, list2)
Obchardon
0

Die Verwendung der __and__Attributmethode funktioniert ebenfalls.

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a).__and__(set(b))
set([5])

oder einfach

>>> set([1, 2, 3, 4, 5]).__and__(set([9, 8, 7, 6, 5]))
set([5])
>>>    
SuperNova
quelle
0
you can | for set union and & for set intersection.
for example:

    set1={1,2,3}
    set2={3,4,5}
    print(set1&set2)
    output=3

    set1={1,2,3}
    set2={3,4,5}
    print(set1|set2)
    output=1,2,3,4,5

curly braces in the answer.
Ravi Tanwar
quelle
4
Die Frage war für Liste und kein Satz. Die Verwendung des &Operators am Set wird bereits von SilentGhost in der akzeptierten Antwort beantwortet
dWinder
0

Ich habe gerade Folgendes verwendet und es hat bei mir funktioniert:

group1 = [1, 2, 3, 4, 5]
group2 = [9, 8, 7, 6, 5]

for k in group1:
    for v in group2:
        if k == v:
            print(k)

Dies würde dann 5 in Ihrem Fall drucken. Wahrscheinlich keine großartige Leistung.

LRBrady
quelle