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


381

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

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

returnMatches(a, b)

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


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]

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


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()ответ по крайней мере так же быстр, как и другие решения, а также наиболее читаемый, он должен быть стандартным решением для этой распространенной проблемы.


Набор фактически удаляет повторы, поэтому в моем случае это не сработает
rgralma

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

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


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.