сравнить два списка, чтобы получить несоответствующие элементы - PullRequest
2 голосов
/ 31 мая 2019

Я проверил это , сравнивая списки , Только один ответ относительно того, что я пытаюсь сделать.У меня есть списки с некоторыми похожими элементами, я хочу получить несовпадающие элементы.

len(h) = 1973182  #h[0] = 'B00006J8F4F2', y[0] = 'B0075Y2X2GO6'
len(y) = 656890

Я делаю

new_list = [i for i in h if i not in y], однако это занимает около 13 минут,Есть ли более быстрый способ сделать это?

В отношении «дублирующего» вопроса, Поиск элементов, отсутствующих в списке , я использую тот же код, что я ищу быстрееспособ сделать это.

Ответы [ 4 ]

2 голосов
/ 31 мая 2019

Вы можете использовать sets, чтобы более эффективно находить разницу между обоими списками. Если вам нужно сохранить порядок в исходном списке, вы можете использовать sorted с key.

Мы хотим отсортировать элементы в наборе в соответствии с их появлением в исходном списке, поэтому одним из способов является создание справочного словаря. Мы можем использовать enumerate для этого. Тогда нам нужно только найти словарь как key функцию:

d = {j:i for i,j in enumerate(h)}
new_list  = sorted(list((set(h) - set(y))), key = lambda x: d[x])

Давайте попробуем на простом примере:

y = range(5)
h = range(7)
d = {j:i for i,j in enumerate(h)}
sorted(list((set(h) - set(y))), key = lambda x: d[x])
# [5, 6]

Сроки -

import random
y = random.sample(range(1, 10001), 10000)
h = random.sample(range(1, 20001), 10000)

%timeit [i for i in h if i not in y]
# 1.28 s ± 37.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

def using_sets(a,b):
    d = {j:i for i,j in enumerate(a)}
    sorted(list((set(a) - set(b))), key = lambda x: d[x])

%timeit using_sets(h,y)
# 6.16 ms ± 373 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Таким образом, есть очевидное улучшение: предлагаемый подход работает в 200 раз быстрее.

0 голосов
/ 31 мая 2019

Вы можете использовать класс Counter из коллекций:

list1 = [1,1,2,3,4]
list2 = [3,3,4,5,6]

from collections import Counter
result = list((Counter(list1)-Counter(list2)).elements())

# [1, 1, 2]

Или, если вы хотите взаимного исключения:

count1 = Counter(list1)
count2 = Counter(list2)
r = list((count1-count2+(count2-count1)).elements()) 

# [1, 1, 2, 3, 5, 6]
0 голосов
/ 31 мая 2019

используется программно и поддерживает порядок и обрабатывает дубликаты в списке1

def function(list1, list2):
    dic2={}   
    for i in list2:
        try:
            if i in dic2.keys():
                pass
        except KeyError:
            dic2[i]=1           

    result =[]
    for i in list1:
        try:
            if i in dic2.keys():
                pass
        except:
            result.append(i)
    return result



list1=[1,2,2,3]
list2=[3,4,5]

solution = function(list1,list2)
print(solution)

выход

[1, 2, 2]

с использованием @yatu h, y list, здесь результат времени

%timeit function(h,y)
2.75 ms ± 22.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
0 голосов
/ 31 мая 2019

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

new_list = [i for i in h if i not in y]

весь список y нуждается в проверке каждый раз для каждого i в h.

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

Вы можете использовать Counter:

from collections import Counter

с двумя списками, скажем

l1 = [1,1,2,3,4]
l2 = [3,3,4,5,6]

для примера, можно использовать подачу в счетчик каждый

>>> Counter(l1)
Counter({1: 2, 2: 1, 3: 1, 4: 1})
>>> Counter(l2)
Counter({3: 2, 4: 1, 5: 1, 6: 1})

Это просто обходит каждый список один раз. Вычитание их дает то, что находится в первом, но не во втором:

>>> Counter(l1)-Counter(l2)
Counter({1: 2, 2: 1})

elements говорит вам, что вы хотите

>>> diff = Counter(l1)-Counter(l2)
>>> list(diff.elements())
[1, 1, 2]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...