Порівняння загальних елементів між двома списками


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)

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

Будь-які ідеї?


1
Привіт, ви можете додати деякі деталі про те, як ви плануєте використовувати код? Якщо це потрібно для виконання завдання, може бути краще вибрати рішення, яке інкапсулює "пітонічний" спосіб. Однак якщо ефективність - це ваша проблема, то навряд чи "пітонічний" спосіб буде найбільш ефективним рішенням. Повідомлення нас у цих деталях допоможе рішенням, спрямованим на вирішення вашої проблеми.
Метт

Відповіді:


278
>>> list1 = [1,2,3,4,5,6]
>>> list2 = [3, 5, 7, 9]
>>> list(set(list1).intersection(list2))
[3, 5]

1
+1, але особисто я використав заморожений, оскільки це незмінне, і тому його можна використовувати як ключ словника тощо
zebrabox

19
Це поверне / унікальні / загальні елементи, але не будь-які повторювані елементи, які можуть існувати.
Дологан

@SilentGhost. Як отримати кількість відповідних елементів з двох списків. У цьому випадку це 2.
Пока

@Poka len (list (set (list1) .intersection (list2)))
Dharmanshu Kamra

2
FYI. Це, безумовно, швидше, ніж рішення, запропоноване Тамасом, але для випадку використання, на який я розглядав, коли опинився на цій сторінці, важливо було зберегти початковий порядок елементів для відфільтрованих елементів. Цей метод втрачає порядок, тоді як метод розуміння списку зберігає порядок. Важливо, якщо комусь це потрібно врахувати. Дякую.
посилення

41

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

A = [1,2,3,4]
B = [2,4,7,8]
commonalities = set(A) - (set(A) - set(B))

4
Це перетворює A на два рази, без зайвих витрат.
wim

36

Рішення, запропоновані S.Mark та SilentGhost, загалом говорять про те, як це слід робити пітонічно, але я подумав, що ви також можете отримати користь від того, чому ваше рішення не працює. Проблема полягає в тому, що як тільки ви знайдете перший спільний елемент у двох списках, ви повертаєте лише цей єдиний елемент. Ваше рішення можна виправити, створивши 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

використовувати встановлені перехрестя, встановити (list1) та встановити (list2)

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

9

Набір - це ще один спосіб вирішити це

a = [3,2,4]
b = [2,3,5]
set(a)&set(b)
{2, 3}

9

list1 = [1,2,3,4,5,6] list2 = [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)

Третій спосіб найшвидший, тому що набори реалізуються за допомогою хеш-таблиць.


8

Попередні відповіді працюють над тим, щоб знайти унікальні загальні елементи, але не вдасться врахувати повторні елементи у списках. Якщо ви хочете, щоб загальні елементи відображалися в тій самій кількості, яку вони зустрічаються у списках, ви можете скористатися наступним однокласником:

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

or TrueЧастина необхідно тільки , якщо ви очікуєте якихось - яких елементів , щоб оцінити в False.


Дивовижне рішення, здається, найбільш ґрунтовне, якщо трішки коротке
Хендека

Це має бути відповідь, яку слід було обрати! Я припускаю, що це працює і для неоднакових списків. Також більшість рішень використовують, setякі не є стабільними (він також втрачає порядок).
життєвий баланс

7

Я порівнював кожен метод, про який згадувала кожна відповідь. На даний момент я використовую 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. метод1: 0,8150673999999999974619413478649221360683441
  2. метод2: 0.8329545000000001531148541289439890533685684
  3. метод3: 0,0016547000000000089414697868051007390022277
  4. метод4: 0,0010262999999999244948867271887138485908508

5

це моя пропозиція, я думаю, що це простіше з наборами, ніж з циклом для

def unique_common_items(list1, list2):
   # Produce the set of *unique* common items in two lists.
   return list(set(list1) & set(list2))

2

Чому б не використовувати list comprehension?

Напівлінійне рішення:

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

0

1) Метод1 збереження list1 - це словник, а потім повторення кожного елему в list2

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) Метод2 за допомогою набору

def findarrayset(a,b):
    common = set(a)&set(b)
    diff=set(a)^set(b)
    print list(common)
    print list(diff) 

-1

Використовуйте генератор:

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). Генератори - це ітерабелі, які часто використовуються замість інших ітерабелів, таких як списки.
ковбасник
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.