2016-12-13 3 views
17

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

main_list=[] 
list_1=["a", "b", "c", "d", "e"] 
list_2=["a", "f", "c", "m"] 

Мне нужно Cicle на list_1 и добавлять на main_list = [] все элементы, которые не соответствуют в list_2.

Результат должен быть таким:

main_list=["f", "m"] 

Как я могу сделать это с питоном?

+1

вы ищете элементы в 'list_2', которые не появляются нигде в' list_1' или элементах в 'list_2', которые отсутствуют в том же индексе в' list_1'? –

ответ

8

(1) Вы можете использовать NumPy's setdiff1d. Из response of Chinny84, если вы обеспокоены тем, с уникальными элементами, а затем:

import numpy as np 
list_1 = ["a", "b", "c", "d", "e"] 
list_2 = ["a", "f", "c", "m"] 
main_list = np.setdiff1d(list_2,list_1) 

(2) В противном случае, используйте main_list = np.setdiff1d(list_2,list_1, assume_unique=True)

Оба ответ даст вам ["f", "m"]. Однако, если list_2 = ["a", "f", "c", "m", "m"], ответ (1) дает ["f", "m"]. Но ответ (2) дает ["f", "m", "m"] (поскольку уникальность каждого элемента в list_2 несущественна).

1

Я бы zip списки вместе, чтобы сравнить их по элементам.

main_list = [b for a, b in zip(list1, list2) if a!= b] 
+0

Если OP хочет сравнить элемент за элементом (это неясно, пример может идти в любом случае), это _much_ более эффективно, чем другие ответы, так как это простой дешевый проход над «списком» с одним новым списком 'строится, нет дополнительных временных рядов, нет дорогих проверок сдерживания и т. д. – ShadowRanger

+0

@ShadowRanger это будет работать только для элементарной разницы, которая является ключевым моментом –

+0

@fordprefect: Yup. [Мой собственный ответ] (https://stackoverflow.com/a/41126821/364696) охватывает независимые от позиции различия. – ShadowRanger

34

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

main_list = list(set(list_2) - set(list_1)) 

Выход:

>>> list_1=["a", "b", "c", "d", "e"] 
>>> list_2=["a", "f", "c", "m"] 
>>> set(list_2) - set(list_1) 
set(['m', 'f']) 
>>> list(set(list_2) - set(list_1)) 
['m', 'f'] 

Per комментарий @JonClements', вот опрятнее версия:

>>> list_1=["a", "b", "c", "d", "e"] 
>>> list_2=["a", "f", "c", "m"] 
>>> list(set(list_2).difference(list_1)) 
['m', 'f'] 
+0

Это хорошо, если мы заботимся только об уникальных элементах, но что, если у нас есть несколько 'm's', например, это не поднимет его. – Chinny84

+0

Это правда. Я предположил, что плакат искал уникальные элементы. Я полагаю, это зависит от того, что он подразумевает под «конкретным». – nrlakin

+0

Действительно p.s. Я не проголосовал за ваш ответ, особенно за непонятный исходный вопрос. – Chinny84

10

Используйте list comprehension например:

main_list = [item for item in list_2 if item not in list_1] 

Выход:

>>> list_1 = ["a", "b", "c", "d", "e"] 
>>> list_2 = ["a", "f", "c", "m"] 
>>> 
>>> main_list = [item for item in list_2 if item not in list_1] 
>>> main_list 
['f', 'm'] 
+1

Примечание: для более крупного 'list_1' вы должны предварительно преобразовать в' set'/'frozenset', например. 'set_1 = frozenset (list_1)', затем 'main_list = [item для item в list_2, если элемент не в set_1]', уменьшая время проверки с 'O (n)' на элемент до (примерно) 'O (1)' , – ShadowRanger

3
main_list=[] 
list_1=["a", "b", "c", "d", "e"] 
list_2=["a", "f", "c", "m"] 

for i in list_2: 
    if i not in list_1: 
     main_list.append(i) 

print(main_list) 

выход:

['f', 'm'] 
+0

Как [решение на основе эквивалентного списка на основе понятий] (http://stackoverflow.com/a/41125957/364696), это будет медленным, если 'list_1' велико, а' list_2' имеет нетривиальный размер, потому что он включает 'len (list_2)' 'O (n)' сканирование 'list_1', что делает его' O (n * m) '(где' n' и 'm' - это длины' list_2' и 'list_1' соответственно). Если вы конвертируете 'list_1' в' set'/'frozenset' вверх, то проверки могут быть выполнены в' O (1) ', что делает общую работу' O (n) 'по длине' list_2' (технически, 'O (max (n, m))', так как вы выполняете 'O (m)' работу, чтобы сделать 'set'). – ShadowRanger

0

Если число вхождений следует принимать во внимание, вероятно, нужно использовать что-то вроде collections.Counter:

list_1=["a", "b", "c", "d", "e"] 
list_2=["a", "f", "c", "m"] 
from collections import Counter 
cnt1 = Counter(list_1) 
cnt2 = Counter(list_2) 
final = [key for key, counts in cnt2.items() if cnt1.get(key, 0) != counts] 

>>> final 
['f', 'm'] 

Как и обещал это также может работать с различным числом вхождений, как «разница»:

list_1=["a", "b", "c", "d", "e", 'a'] 
cnt1 = Counter(list_1) 
cnt2 = Counter(list_2) 
final = [key for key, counts in cnt2.items() if cnt1.get(key, 0) != counts] 

>>> final 
['a', 'f', 'm'] 
1

Если вы хотите раствор один вкладыш (без учета импорта), что требует только O(max(n, m)) работы на входах длины n и m, не O(n * m) работы, вы можете сделать это с the itertools module:

from itertools import filterfalse 

main_list = list(filterfalse(set(list_1).__contains__, list_2)) 

Это имеет преимущество функциональных функций, принимающих функцию обратного вызова по конструкции ion, позволяя ему создать обратный вызов один раз и повторно использовать его для каждого элемента без необходимости его хранить где-нибудь (потому что filterfalse хранит его внутри); список понятий и выражений генератора может это сделать, но это уродливо.†

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

main_list = [x for x in list_2 if x not in list_1] 

со скоростью:

set_1 = set(list_1) 
main_list = [x for x in list_2 if x not in set_1] 

Конечно, если сравнения предназначены позиционным, так:

list_1 = [1, 2, 3] 
list_2 = [2, 3, 4] 

следует производить:

main_list = [2, 3, 4] 

(поскольку значение в list_2 имеет матч в тот же индекс в list_1), вы должны обязательно идти с Patrick's answer, который не включает в себя никаких временных list с или set с (даже с set s быть примерно O(1), они имеют более высокий «постоянный» коэффициент за проверку, чем простые проверки равенства) и включает в себя O(min(n, m)), меньше, чем любой другой ответ, и если ваша проблема чувствительна к положению, является единственным правилом , когда соответствующие элементы появляются при несоответствующих смещениях.

†: Способ сделать то же самое со списком пониманием как однострочник будет злоупотреблять вложенное зацикливание для создания и значение кэша (s) в «внешней» петле, например:

main_list = [x for set_1 in (set(list_1),) for x in list_2 if x not in set_1] 

, который также дает незначительное преимущество в производительности на Python 3 (потому что теперь set_1 локально ограничен кодом понимания, а не просматривается из вложенной области для каждой проверки; на Python 2 это не имеет значения, поскольку Python 2 не используйте закрытие для понимания списков, они работают в том же объеме, в котором они используются).

10

Не знаю, почему выше объяснение настолько сложно, когда у вас есть собственные методы, доступные:

main_list = list(set(list_2)-set(list_1)) 
+0

Может быть причиной сохранения порядка – Keith

Смежные вопросы