Porównanie wspólnych elementów między 2 listami

143
def common_elements(list1, list2):
    """
    Return a list containing the elements which are in both list1 and list2

    >>> common_elements([1,2,3,4,5,6], [3,5,7,9])
    [3, 5]
    >>> common_elements(['this','this','n','that'],['this','not','that','that'])
    ['this', 'that']
    """
    for element in list1:
        if element in list2:
            return list(element)

Mam to do tej pory, ale wydaje się, że nie mogę tego uruchomić!

Jakieś pomysły?

Daniel
źródło
1
Cześć, czy mógłbyś dodać więcej szczegółów na temat tego, jak planujesz używać kodu? Jeśli ma to zakończyć zadanie, może być lepiej wybrać rozwiązanie, które zawiera w sobie sposób „Pythonic”. Jeśli jednak zależy Ci na wydajności, metoda „Pythonic” prawdopodobnie nie będzie najbardziej wydajnym rozwiązaniem. Poinformowanie nas o tych szczegółach pomoże w rozwiązaniu problemu.
Matt C

Odpowiedzi:

278
>>> list1 = [1,2,3,4,5,6]
>>> list2 = [3, 5, 7, 9]
>>> list(set(list1).intersection(list2))
[3, 5]
SilentGhost
źródło
1
+1, ale osobiście użyłem Frozenset, ponieważ jest niezmienny i może być używany jako klucz do słownika itp.
zebrabox
19
Spowoduje to zwrócenie elementów / unique / common, ale nie jakichkolwiek powtarzających się elementów, które mogą istnieć.
Dologan
@SilentGhost. Jak uzyskać liczbę dopasowanych elementów z dwóch list. W tym przypadku jest to 2.
Poka
@Poka len (list (set (list1) .intersection (list2)))
Dharmanshu Kamra
2
FYI. Jest to zdecydowanie szybsze rozwiązanie, niż rozwiązanie zaproponowane przez Tamása, ale w przypadku użycia, na który patrzyłem, kiedy trafiłem na tę stronę, ważne było zachowanie oryginalnej kolejności elementów dla elementów po filtracji. Ta metoda traci kolejność, podczas gdy metoda rozumienia listy zachowuje kolejność. Ważne, jeśli ktoś musi to rozważyć. Dzięki.
agftrading
41

Możesz także użyć zestawów i uzyskać podobieństwa w jednej linii: odejmij zestaw zawierający różnice od jednego z zestawów.

A = [1,2,3,4]
B = [2,4,7,8]
commonalities = set(A) - (set(A) - set(B))
BeyondRubicon
źródło
4
To konwertuje A do ustawienia podwójnego, niepotrzebnie marnotrawstwa.
wim
36

Rozwiązania sugerowane przez S.Mark i SilentGhost ogólnie mówią ci, jak należy to zrobić w Pythonie, ale pomyślałem, że możesz również skorzystać na wiedzy, dlaczego twoje rozwiązanie nie działa. Problem polega na tym, że gdy tylko znajdziesz pierwszy wspólny element na dwóch listach, zwracasz tylko ten pojedynczy element. Twoje rozwiązanie można naprawić, tworząc resultlistę i zbierając typowe elementy na tej liście:

def common_elements(list1, list2):
    result = []
    for element in list1:
        if element in list2:
            result.append(element)
    return result

Jeszcze krótsza wersja wykorzystująca wyrażenia listowe:

def common_elements(list1, list2):
    return [element for element in list1 if element in list2]

Jednak, jak powiedziałem, jest to bardzo nieefektywny sposób zrobienia tego - wbudowane typy zestawów w Pythonie są o wiele bardziej wydajne, ponieważ są implementowane wewnętrznie w C.

Tamás
źródło
1
Świetne dla obu propozycji
dlewin
1
UWAGA: Powyższe metody działają tylko w przypadku list o jednakowej wielkości. Jeśli pracujesz z listami o różnej wielkości, tak jak ja, to przed wywołaniem funkcji musisz ocenić kolejność w oparciu o len (): list1 = [2,2,2], list2 [2,3] -> [2,2,2] list1 = [2,3], list2 [2,2,2] -> [2]
redthumb
29

użyj zestawu przecięć, set (lista1) i set (lista2)

>>> def common_elements(list1, list2):
...     return list(set(list1) & set(list2))
...
>>>
>>> common_elements([1,2,3,4,5,6], [3,5,7,9])
[3, 5]
>>>
>>> common_elements(['this','this','n','that'],['this','not','that','that'])
['this', 'that']
>>>
>>>

Zwróć uwagę, że lista wyników może mieć inną kolejność niż oryginalna lista.

TY
źródło
Dzięki za pomoc. Zrozum, gdzie popełniłem błąd i nad czym pracować następnym razem. :)
Daniel
5
świetne rozwiązanie. czy jest też sposób na zachowanie porządku dzięki temu?
tarrasch
14

możesz użyć prostego rozumienia listy:

x=[1,2,3,4]
y=[3,4,5]
common = [i for i in x if i in y]
common: [3,4]
Mahdi Ghelichi
źródło
9

Zestaw to kolejny sposób na rozwiązanie tego problemu

a = [3,2,4]
b = [2,3,5]
set(a)&set(b)
{2, 3}
nEO
źródło
9

list1 = [1,2,3,4,5,6] list2 = [3,5,7,9]

Wiem, że można to rozwiązać na 3 sposoby.Oczywiście może być więcej.

1-

common_elements = [e for e in list1 if e in list2]

2-

import numpy as np
common_elements = np.intersect1d(list1, list2)

3-

common_elements = set(list1).intersection(list2)

Trzeci sposób jest najszybszy, ponieważ zestawy są implementowane przy użyciu tabel skrótów.

Mahmoud Reda
źródło
8

Wszystkie poprzednie odpowiedzi służą do znalezienia unikalnych wspólnych elementów, ale nie uwzględniają powtarzających się pozycji na listach. Jeśli chcesz, aby wspólne elementy pojawiały się w tej samej liczbie, w jakiej występują wspólne na listach, możesz użyć następującej jednolinijki:

l2, common = l2[:], [ e for e in l1 if e in l2 and (l2.pop(l2.index(e)) or True)]

Ta or Trueczęść jest konieczna tylko wtedy, gdy oczekujesz, że jakiekolwiek elementy zostaną ocenione False.

Dologan
źródło
Niesamowite rozwiązanie, wydaje się najdokładniejsze, choć trochę lakoniczne
Hendeca
To powinna być odpowiedź, która powinna była zostać wybrana! Zakładam, że działa to również w przypadku nierównych list. Również większość rozwiązań używa setniestabilności (czyli utraty kolejności).
saldo ratunkowe
7

Porównałem każdą z metod wymienionych w każdej odpowiedzi. W tej chwili używam Pythona 3.6.3 do tej implementacji. Oto kod, którego użyłem:

import time
import random
from decimal import Decimal


def method1():
    common_elements = [x for x in li1_temp if x in li2_temp]
     print(len(common_elements))


def method2():
    common_elements = (x for x in li1_temp if x in li2_temp)
    print(len(list(common_elements)))


def method3():
    common_elements = set(li1_temp) & set(li2_temp)
    print(len(common_elements))


def method4():
    common_elements = set(li1_temp).intersection(li2_temp)
    print(len(common_elements))


if __name__ == "__main__":
    li1 = []
    li2 = []
    for i in range(100000):
        li1.append(random.randint(0, 10000))
        li2.append(random.randint(0, 10000))

    li1_temp = list(set(li1))
    li2_temp = list(set(li2))

    methods = [method1, method2, method3, method4]
    for m in methods:
        start = time.perf_counter()
        m()
        end = time.perf_counter()
        print(Decimal((end - start)))

Jeśli uruchomisz ten kod, zobaczysz, że jeśli używasz listy lub generatora (jeśli iterujesz po generatorze, a nie tylko go używasz. Zrobiłem to, gdy zmusiłem generator do wydrukowania jego długości), uzyskasz prawie taką samą wydajność. Ale jeśli użyjesz zestawu, uzyskasz znacznie lepszą wydajność. Również jeśli użyjesz metody przecięcia, uzyskasz trochę lepszą wydajność. wynik każdej metody w moim komputerze jest wymieniony poniżej:

  1. metoda1: 0.8150673999999999974619413478649221360683441
  2. metoda2: 0.8329545000000001531148541289439890533685684
  3. method3: 0,0016547000000000089414697868051007390022277
  4. method4: 0,0010262999999999244948867271887138485908508
Saber Solooki
źródło
5

to jest moja propozycja, myślę, że jest to łatwiejsze z zestawami niż z pętlą for

def unique_common_items(list1, list2):
   # Produce the set of *unique* common items in two lists.
   return list(set(list1) & set(list2))
Elasri
źródło
2

Dlaczego nie używać list comprehension?

Rozwiązanie pół linii:

common_elements = [x for x in list1 if x in list2]
seralouk
źródło
0

1) Metoda 1 zapisująca list1 jest słownikiem, a następnie iteruje każdy element z listy2

def findarrayhash(a,b):
    h1={k:1 for k in a}
    for val in b:
        if val in h1:
            print("common found",val)
            del h1[val]
        else:
            print("different found",val)
    for key in h1.iterkeys():
        print ("different found",key)

Znajdowanie wspólnych i różnych elementów:

2) Metoda 2 przy użyciu zestawu

def findarrayset(a,b):
    common = set(a)&set(b)
    diff=set(a)^set(b)
    print list(common)
    print list(diff) 
JS
źródło
-1

Użyj generatora:

common = (x for x in list1 if x in list2)

Zaletą jest to, że powróci w stałym czasie (prawie natychmiast), nawet w przypadku korzystania z ogromnych list lub innych ogromnych iteracji.

Na przykład,

list1 =  list(range(0,10000000))
list2=list(range(1000,20000000))
common = (x for x in list1 if x in list2)

Wszystkie inne odpowiedzi tutaj zajmą bardzo dużo czasu z tymi wartościami dla list1 i list2.

Następnie możesz powtórzyć odpowiedź za pomocą

for i in common: print(i)

Lub przekonwertuj go na listę z

list(i)
cowlinator
źródło
To nie daje odpowiedzi. Rezultatem jest raczej generator niż lista wspólnych elementów.
josiekre
1
Prawidłowo, tworzy generator, który jest odpowiedzią. Chodziło o to, aby jakoś uzyskać wspólne elementy dwóch list, co robi ten generator. Po prostu iteracyjne generator tak: for i in common: print(i). Generatory to elementy iteracyjne, które są często używane zamiast innych elementów iteracyjnych, takich jak listy.
cowlinator