Сравнение общих элементов между 2 списками

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

Получил это до сих пор, но не могу заставить его работать!

Любые идеи?

Даниэль
источник
1
Привет, не могли бы вы добавить некоторые подробности о том, как вы планируете использовать код? Если это необходимо для выполнения задания, может быть лучше выбрать решение, которое инкапсулирует «питонический» путь. Однако, если вас беспокоит эффективность, то «питонический» способ вряд ли будет наиболее эффективным решением. Если вы сообщите нам об этих деталях, это поможет решить вашу проблему.
Matt C

Ответы:

295
>>> list1 = [1,2,3,4,5,6]
>>> list2 = [3, 5, 7, 9]
>>> list(set(list1).intersection(list2))
[3, 5]
Тихий призрак
источник
1
+1 но лично я использовал frozenset, поскольку он неизменяемый и поэтому может использоваться как ключ словаря и т. Д.
zebrabox
19
Это вернет элементы / unique / common, но не любые повторяющиеся элементы, которые могут существовать.
Dologan
@SilentGhost. Как получить количество совпадающих элементов из двух списков. В этом случае 2.
Poka
@Poka len (list (set (list1) .intersection (list2)))
Дхарманшу Камра
2
К вашему сведению. Это определенно быстрее, чем решение, предложенное Тамасом, но для случая использования, который я рассматривал, когда оказался на этой странице, было важно сохранить исходный порядок элементов для постфильтрованных элементов. Этот метод теряет порядок, тогда как метод понимания списка сохраняет порядок. Важно, если кому-то нужно это учитывать. Спасибо.
agftrading 01
42

Вы также можете использовать наборы и получить общие черты в одной строке: вычтите набор, содержащий различия, из одного из наборов.

A = [1,2,3,4]
B = [2,4,7,8]
commonalities = set(A) - (set(A) - set(B))
BeyondRubicon
источник
4
Это превращает A в набор дважды, что излишне расточительно.
wim
37

Решения, предложенные S.Mark и SilentGhost, обычно говорят вам, как это должно быть сделано в Python, но я подумал, что вам также может быть полезно узнать, почему ваше решение не работает. Проблема в том, что как только вы найдете первый общий элемент в двух списках, вы вернете только этот единственный элемент. Ваше решение можно исправить, создав resultсписок и собрав общие элементы в этом списке:

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

Еще более короткая версия с использованием списков:

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

Однако, как я уже сказал, это очень неэффективный способ сделать это - встроенные в Python типы наборов намного эффективнее, поскольку они реализованы на C внутри.

Тамаш
источник
1
Отлично
подходит
1
ПРИМЕЧАНИЕ. Вышеуказанные методы работают только для списков одинакового размера. Если вы работаете со списками неравного размера, как я, то вам нужно будет оценить порядок на основе len () до вызова функции: list1 = [2,2,2], list2 [2,3] -> [2,2,2] list1 = [2,3], list2 [2,2,2] -> [2]
redthumb
29

использовать набор пересечений, установить (список1) и установить (список2)

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

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

ВЫ
источник
Спасибо за помощь. Поймите, где я ошибся и над чем работать в следующий раз. :)
Даниэль
5
отличное решение. есть ли способ сохранить с этим порядок?
tarrasch
14

вы можете использовать простое понимание списка:

x=[1,2,3,4]
y=[3,4,5]
common = [i for i in x if i in y]
common: [3,4]
Махди Геличи
источник
14

список1 = [1,2,3,4,5,6] список2 = [3,5,7,9]

Я знаю 3 способа решить эту проблему. Конечно, может быть и больше.

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)

Третий способ - самый быстрый, потому что наборы реализованы с использованием хеш-таблиц.

Махмуд Реда
источник
9

Все предыдущие ответы работают над поиском уникальных общих элементов, но не учитывают повторяющиеся элементы в списках. Если вы хотите, чтобы общие элементы отображались под тем же номером, что и общие в списках, вы можете использовать следующий однострочник:

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

Эта or Trueчасть необходима только в том случае, если вы ожидаете, что какие-либо элементы будут оцениваться False.

Дологан
источник
Замечательное решение, кажется, самое тщательное, хотя и немного краткое
Hendeca
Это должен быть ответ, который следовало выбрать! Я предполагаю, что это также работает для неравных списков. Также в большинстве решений используются setнестабильные решения (то есть порядок теряется).
lifebalance
9

Set - еще один способ решить эту проблему

a = [3,2,4]
b = [2,3,5]
set(a)&set(b)
{2, 3}
нео
источник
8

Я сравнил каждый из методов, упомянутых в каждом ответе. На данный момент я использую для этой реализации python 3.6.3. Это код, который я использовал:

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

Если вы запустите этот код, вы увидите, что если вы используете список или генератор (если вы выполняете итерацию по генератору, а не просто используете его. Я сделал это, когда заставил генератор печатать длину его), вы получите почти такую ​​же производительность. Но если вы используете набор, вы получите гораздо лучшую производительность. Также, если вы используете метод пересечения, вы получите немного лучшую производительность. результат каждого метода на моем компьютере указан ниже:

  1. method1: 0.8150673999999999974619413478649221360683441
  2. method2: 0.8329545000000001531148541289439890533685684
  3. method3: 0.0016547000000000089414697868051007390022277
  4. method4: 0.0010262999999999244948867271887138485908508
Сабер Солооки
источник
5

это мое предложение, я думаю, что с наборами проще, чем с циклом for

def unique_common_items(list1, list2):
   # Produce the set of *unique* common items in two lists.
   return list(set(list1) & set(list2))
Эласри
источник
4

Просто используйте list comprehension.

Половинное решение:

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

Если это помогло, подумайте о том, чтобы проголосовать за мой ответ.

Seralouk
источник
0

1) Метод1, сохраняющий список1, является словарем, а затем повторяет каждый элемент в списке2

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)

Поиск общих и разных элементов:

2) Method2 с использованием набора

def findarrayset(a,b):
    common = set(a)&set(b)
    diff=set(a)^set(b)
    print list(common)
    print list(diff) 
JS
источник
-2

Используйте генератор:

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

Преимущество здесь в том, что это будет возвращаться в постоянное время (почти мгновенно) даже при использовании огромных списков или других огромных итераций.

Например,

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

Все остальные ответы здесь займут очень много времени с этими значениями для list1 и list2.

Затем вы можете повторить ответ с помощью

for i in common: print(i)

Или преобразуйте его в список с помощью

list(i)
ковбойник
источник
Это не дает ответа. В результате получается генератор, а не список общих элементов.
josiekre
1
Правильно, он создает генератор, который и есть ответ. Вопрос заключался в том, чтобы как-то получить общие элементы двух списков, что и делает этот генератор. Просто итерация генератора так: for i in common: print(i). Генераторы - это итерируемые объекты, которые часто используются вместо других итераций, таких как списки.
cowlinator