Как я могу сравнить два списка в Python и вернуть совпадения

381

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

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

returnMatches(a, b)

вернется [5], например.

tehryan
источник
4
Ответы ниже всего кажутся мне неправильными. Что произойдет, если число будет повторяться в любом списке, наверняка вы захотите знать, что (?) (Например, скажем, в обоих списках дважды по 5). Любое решение, использующее наборы, немедленно удалит все повторяющиеся элементы, и вы потеряете эта информация
MH
Возможный дубликат Как найти пересечение списка?
Кушан Гунасекера

Ответы:

487

Не самый эффективный, но самый очевидный способ сделать это:

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

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

SilentGhost
источник
15
Внимание, понимание списка не обязательно является более быстрым вариантом. Для больших наборов (где производительность, скорее всего, имеет значение) побитовое сравнение ( &) или set(a).intersection(b)будет таким же быстрым или быстрым, чем понимание списка.
Джошмейкер
24
Еще одно предостережение: понимание списка находит значения, которые появляются в тех же самых позициях (это то, что SilentGhost имел в виду под «порядком важен»). Заданные решения пересечения также найдут совпадения в РАЗНЫХ позициях. Это ответы на 2 совершенно разных вопроса ... (вопрос
опа
Как это сделать, если ваши списки являются списками списков, т.е. a = [[0,0], [1,0]] и b = [[2,3], [0,0]]
Schneems
3
Какова будет временная сложность первого примера set(a) & set(b)?
АдъюнктПрофессорФалькон
Обратите внимание, что это не работает, если оба набора пусты, и вы ожидаете, что сравнение пройдет. Поэтому измените на «(установите (а) и установите (б)) или (не а и не б)»
Нил МакГилл,
395

Используйте set.intersection () , это быстро и читабельно.

>>> set(a).intersection(b)
set([5])
Деннис
источник
28
Этот ответ имеет хорошую алгоритмическую производительность, поскольку только один из списков (более короткий должен быть предпочтительным) превращается в набор для быстрого поиска, а другой список просматривается при поиске его элементов в наборе.
u0b34a0f6ae
18
bool(set(a).intersection(b))для TrueилиFalse
Акшай
6
Этот ответ является более гибким и читаемым, так как люди могут нуждаться differenceили union.
Шихе Чжан
Что, если у меня есть объекты в качестве элементов списка и я хочу только частичное совпадение, т. Е. Только некоторые атрибуты должны совпадать, чтобы он считался соответствующим объектом?
CGFoX,
Есть ли разница в производительности для .intersection()против &?
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()ответ по крайней мере так же быстр, как и другие решения, а также наиболее читаемый, он должен быть стандартным решением для этой распространенной проблемы.

Joshmaker
источник
Набор фактически удаляет повторы, поэтому в моем случае это не сработает
rgralma
@rgralma создание нового setиз существующего listничего не удалит из оригинала list. Если вы хотите, чтобы специальная логика обрабатывала дубликаты в списке, я думаю, вам нужно задать новый вопрос, потому что ответ должен быть конкретным для того, как вы хотите обрабатывать дубликаты.
Джошмейкер
67

Я предпочитаю ответы на основе набора, но вот тот, который работает в любом случае

[x for x in a if x in b]
SingleNegationElimination
источник
15

Самый простой способ сделать это - использовать наборы :

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a) & set(b)
set([5])
Грег Хьюгилл
источник
15

Быстрый способ:

list(set(a).intersection(set(b)))
DisplacedAussie
источник
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)
Mushfiq
источник
5

Хотите дубликаты? Если нет, то, возможно, вам следует использовать наборы вместо:


>>> set([1, 2, 3, 4, 5]).intersection(set([9, 8, 7, 6, 5]))
set([5])
Тимоти Пратли
источник
Если вы действительно хотите списки, java2s.com/Code/Python/List/Functiontointersecttwolists.htm >>> intersect ([1, 2, 3, 4, 5], [9, 8, 7, 6, 5]) [5 ]
Тимоти Пратли
Согласно документу - ... исключаются подверженные ошибкам конструкции, такие как Set ('abc') и 'cbs', в пользу более читабельного Set ('abc'). Intersection ('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 
Хариш Верма
источник
1
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и / или почему он решает проблему, улучшит долгосрочную ценность ответа.
Дональд Дак
4

Можно также использовать itertools.product.

>>> common_elements=[]
>>> for i in list(itertools.product(a,b)):
...     if i[0] == i[1]:
...         common_elements.append(i[0])
SuperNova
источник
3

Ты можешь использовать

def returnMatches(a,b):
       return list(set(a) & set(b))
Прабху
источник
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])
>>>    
SuperNova
источник
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 в вашем случае. Вероятно, не очень хорошая производительность, хотя.

LRBrady
источник