Як я можу порівняти два списки в матчах python та return


379

Я хочу взяти два списки і знайти значення, які відображаються в обох.

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

returnMatches(a, b)

повернеться [5], наприклад.


4
Відповіді нижче мені здаються неправильними. Що станеться, якщо число повторюється в будь-якому списку, напевно, ви хочете знати, що (?) (Наприклад, скажімо, що обидва списки мають "5" двічі) Будь-яке рішення, що використовує набори, негайно видалить усі повторювані елементи, і ви втратите та інформація.
MH

Відповіді:


486

Не найефективніший, але, безумовно, найбільш очевидний спосіб це зробити:

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

якщо замовлення є значним, ви можете зробити це з таким розумінням списку:

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

(працює лише для списків однакового розміру, що передбачає значущість порядку).


15
Примітка обережності, розуміння списку не обов'язково є швидшим варіантом. Для більших наборів (де продуктивність, швидше за все, має значення) побітове порівняння ( &) або set(a).intersection(b)буде таким же швидким або швидшим, ніж розуміння списку.
Joshmaker

24
Ще одна обережність: розуміння списку знаходить значення, які відображаються в обох позиціях SAME (це те, що SilentGhost мається на увазі під "порядком є ​​значущим"). Встановлені рішення перехрестя також знайдуть збіги у РІЗНИХ положеннях. Це відповіді на 2 досить різні запитання ... (питання ОП неоднозначне, щодо якого воно
задається

Як це зробити, якщо у списках є списки списків, тобто a = [[0,0], [1,0]] і b = [[2,3], [0,0]]
Шнеем

3
Якою була б часова складність першого прикладу set(a) & set(b)?
AdjunctProfessorFalcon

Зверніть увагу, це не працює, якщо обидва набори порожні, і ви очікуєте проходження порівняння. Тож змініть на "(set (a) та set (b)) or (not a and not b)"
Ніл Макгілл

395

Використовуйте set.intersection () , це швидко і легко читається.

>>> set(a).intersection(b)
set([5])

28
Ця відповідь має хороші алгоритмічні показники, оскільки лише один із списків (кращий слід віддати перевагу) перетворюється на набір для швидкого пошуку, а інший список проходить, шукаючи його елементи в наборі.
u0b34a0f6ae

18
bool(set(a).intersection(b))для TrueабоFalse
Акшай

6
Ця відповідь є більш гнучкою та зрозумілою, оскільки люди можуть потребувати differenceчи union.
Shihe Zhang

Що робити, якщо я маю об'єкти як елементи списку і хочу лише часткові збіги, тобто лише деякі атрибути повинні відповідати, щоб він вважався об'єктом, що відповідає?
CGFoX

Чи є різниця в продуктивності для .intersection()vs &?
brandonbanks

106

Швидкий тест на ефективність, який показує рішення Лутза, є найкращим:

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)

Ось результати на моїй машині:

# 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

Очевидно, що будь-який тест на штучну працездатність слід брати із зерном солі, але оскільки set().intersection()відповідь принаймні настільки ж швидкий, як інші рішення, а також найбільш читабельний, це має бути стандартним рішенням цієї поширеної проблеми.


Набір насправді видаляє повтори, тому в моєму випадку
звичайна

@rgralma створення нового setз існуючого listнічого не видалить із оригіналу list. Якщо ви хочете, щоб спеціальна логіка обробляла дублікати всередині списку, я думаю, вам потрібно буде задати нове запитання, тому що відповідь повинна бути конкретна для того, як ви хочете обробляти дублікати.
Joshmaker

67

Я вважаю за краще відповіді, засновані на наборі, але ось такий, який працює в будь-якому випадку

[x for x in a if x in b]



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

1
Прийнята відповідь не працює для списків, що містять рядки. Цей робить.
Антоній

12

Також ви можете спробувати це, зберігаючи загальні елементи в новому списку.

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

5

Ви хочете дублікати? Якщо ні, можливо, вам слід використовувати набори:


>>> set([1, 2, 3, 4, 5]).intersection(set([9, 8, 7, 6, 5]))
set([5])

Якщо списки дуже потрібні, java2s.com/Code/Python/List/Functiontointersecttwolists.htm >>> перетинаються ([1, 2, 3, 4, 5], [9, 8, 7, 6, 5]) [5 ]
Тімоті Пратлі

Згідно з doc - ... виключає конструкції, схильні до помилок, такі як Set ('abc') і 'cbs' на користь більш читаного набору ('abc'). Перехрестя ('cbs'). - docs.python.org/library/sets.html
Аарон Ньютон,

5

ще один трохи більш функціональний спосіб перевірити рівність списку для списку 1 (lst1) та списку 2 (lst2), де об'єкти мають глибину першої і який зберігає порядок:

all(i == j for i, j in zip(lst1, lst2))   

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 

Хоча цей код може відповісти на питання, надаючи додатковий контекст щодо того, як та / або чому він вирішує проблему, покращить довгострокове значення відповіді.
Дональд Дак

4

Можна також використовувати itertools.product.

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


3

Ви можете використовувати:

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

Вихід:

set([1, 7, 9])

4
чим це відрізняється від прийнятої відповіді від 6+ років тому?
tmdavison

1
Ну, я написав повну деталь з результатом і добре для початківця пітона
Аднана Гафара

2

Якщо ви бажаєте булевого значення:

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

1

Наступне рішення працює для будь-якого порядку елементів списку, а також підтримує обидва списки різної довжини.

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]

1
Numpy має для цього специфічну функцію:np.intersect1d(list1, list2)
obchardon

0

Використання __and__методу атрибутів також працює.

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

або просто

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

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.

4
Питання було для списку і не було встановлено. використання &оператора на наборі вже відповідає SilentGhost у прийнятій відповіді
dWinder

0

Я просто використав наступне, і це працювало для мене:

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)

тоді це буде надруковано 5 у вашому випадку. Напевно, не дуже велика ефективність, хоча.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.