Вопрос

У меня есть два списка в Python, как эти:

temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']

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

temp3 = ['Three', 'Four']

Есть ли быстрые способы без циклов и проверки?

Это было полезно?

Решение

In [5]: list(set(temp1) - set(temp2))
Out[5]: ['Four', 'Three']

Остерегайтесь

In [5]: set([1, 2]) - set([2, 3])
Out[5]: set([1]) 

где вы можете ожидать / хотите, чтобы равняться set([1, 3]). Отказ Если вы хотите set([1, 3]) Как ваш ответ, вам нужно будет использовать set([1, 2]).symmetric_difference(set([2, 3])).

Другие советы

Существующие решения все предлагают либо одно или другое:

  • Быстрее, чем o (n * m) производительность.
  • Сохранить порядок ввода списка.

Но пока нет решения оба. Если вы хотите оба, попробуйте это:

s = set(temp2)
temp3 = [x for x in temp1 if x not in s]

Тест производительности

import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print timeit.timeit('list(set(temp1) - set(temp2))', init, number = 100000)
print timeit.timeit('s = set(temp2);[x for x in temp1 if x not in s]', init, number = 100000)
print timeit.timeit('[item for item in temp1 if item not in temp2]', init, number = 100000)

Результаты:

4.34620224079 # ars' answer
4.2770634955  # This answer
30.7715615392 # matt b's answer

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

init = '''
temp1 = [str(i) for i in range(100000)]
temp2 = [str(i * 2) for i in range(50)]
'''

Результаты:

11.3836875916 # ars' answer
3.63890368748 # this answer (3 times faster!)
37.7445402279 # matt b's answer
temp3 = [item for item in temp1 if item not in temp2]

Разница между двумя списками (скажем, List1 и List2) можно найти с помощью следующей простой функции.

def diff(list1, list2):
    c = set(list1).union(set(list2))  # or c = set(list1) | set(list2)
    d = set(list1).intersection(set(list2))  # or d = set(list1) & set(list2)
    return list(c - d)

или

def diff(list1, list2):
    return list(set(list1).symmetric_difference(set(list2)))  # or return list(set(list1) ^ set(list2))

Используя вышеуказанную функцию, разница может быть найдена с использованием diff(temp2, temp1) или diff(temp1, temp2). Отказ Оба дадут результат ['Four', 'Three']. Отказ Вам не нужно беспокоиться о порядке постановления списка, либо в какой список должен быть дан первый.

Справочник Python DOC.

Если вы хотите разницу рекурсивно, я написал пакет для Python:https://github.com/seperman/deepdift.

Установка

Установите из pypi:

pip install deepdiff

Пример использования

Импорт

>>> from deepdiff import DeepDiff
>>> from pprint import pprint
>>> from __future__ import print_function # In case running on Python 2

Тот же объект возвращает пустой

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = t1
>>> print(DeepDiff(t1, t2))
{}

Тип элемента изменился

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:"2", 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{ 'type_changes': { 'root[2]': { 'newtype': <class 'str'>,
                                 'newvalue': '2',
                                 'oldtype': <class 'int'>,
                                 'oldvalue': 2}}}

Значение элемента изменилось

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:4, 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

Добавлен товар и / или удален

>>> t1 = {1:1, 2:2, 3:3, 4:4}
>>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff)
{'dic_item_added': ['root[5]', 'root[6]'],
 'dic_item_removed': ['root[4]'],
 'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

Струнная разница

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}}
>>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { 'root[2]': {'newvalue': 4, 'oldvalue': 2},
                      "root[4]['b']": { 'newvalue': 'world!',
                                        'oldvalue': 'world'}}}

Струнная разница 2

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!\nGoodbye!\n1\n2\nEnd"}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n1\n2\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { "root[4]['b']": { 'diff': '--- \n'
                                                '+++ \n'
                                                '@@ -1,5 +1,4 @@\n'
                                                '-world!\n'
                                                '-Goodbye!\n'
                                                '+world\n'
                                                ' 1\n'
                                                ' 2\n'
                                                ' End',
                                        'newvalue': 'world\n1\n2\nEnd',
                                        'oldvalue': 'world!\n'
                                                    'Goodbye!\n'
                                                    '1\n'
                                                    '2\n'
                                                    'End'}}}

>>> 
>>> print (ddiff['values_changed']["root[4]['b']"]["diff"])
--- 
+++ 
@@ -1,5 +1,4 @@
-world!
-Goodbye!
+world
 1
 2
 End

Тип смены

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n\n\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'type_changes': { "root[4]['b']": { 'newtype': <class 'str'>,
                                      'newvalue': 'world\n\n\nEnd',
                                      'oldtype': <class 'list'>,
                                      'oldvalue': [1, 2, 3]}}}

Разница в списке

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{'iterable_item_removed': {"root[4]['b'][2]": 3, "root[4]['b'][3]": 4}}

Разница списка 2:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'iterable_item_added': {"root[4]['b'][3]": 3},
  'values_changed': { "root[4]['b'][1]": {'newvalue': 3, 'oldvalue': 2},
                      "root[4]['b'][2]": {'newvalue': 2, 'oldvalue': 3}}}

Разница списка игнорирующая порядок или дубликаты: (с одинаковыми словарями, что и выше)

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2, ignore_order=True)
>>> print (ddiff)
{}

Список, который содержит словарь:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'dic_item_removed': ["root[4]['b'][2][2]"],
  'values_changed': {"root[4]['b'][2][1]": {'newvalue': 3, 'oldvalue': 1}}}

Наборы:

>>> t1 = {1, 2, 8}
>>> t2 = {1, 2, 3, 5}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (DeepDiff(t1, t2))
{'set_item_added': ['root[3]', 'root[5]'], 'set_item_removed': ['root[8]']}

Названные кортежи:

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> t1 = Point(x=11, y=22)
>>> t2 = Point(x=11, y=23)
>>> pprint (DeepDiff(t1, t2))
{'values_changed': {'root.y': {'newvalue': 23, 'oldvalue': 22}}}

Пользовательские объекты:

>>> class ClassA(object):
...     a = 1
...     def __init__(self, b):
...         self.b = b
... 
>>> t1 = ClassA(1)
>>> t2 = ClassA(2)
>>> 
>>> pprint(DeepDiff(t1, t2))
{'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}

Атрибут объекта Добавлен:

>>> t2.c = "new attribute"
>>> pprint(DeepDiff(t1, t2))
{'attribute_added': ['root.c'],
 'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}

Если вы действительно смотрите в производительность, то используйте Numpy!

Вот полная ноутбука в качестве гейста на GitHub со сравнением между списком, Numpy и Pands.

https://gist.github.com/denfromufa/2821ff59b02e9482be15d27f2bbd4451.

enter image description here

самый простой способ,

использовать Установить (). Разница (set ())

list_a = [1,2,3]
list_b = [2,3]
print set(list_a).difference(set(list_b))

Ответ set([1])

можно печатать как список,

print list(set(list_a).difference(set(list_b)))

Я буду бросать, поскольку ни один из настоящих решений не дает кортеж:

temp3 = tuple(set(temp1) - set(temp2))

В качестве альтернативы:

#edited using @Mark Byers idea. If you accept this one as answer, just accept his instead.
temp3 = tuple(x for x in temp1 if x not in set(temp2))

Как другой не кортеж, уступающий ответы в этом направлении, он сохраняет порядок

Можно сделать с помощью оператора Python XOR.

  • Это удалит дубликаты в каждом списке
  • Это покажет разницу Temp1 от Temp2 и Temp2 из Temp1.

set(temp1) ^ set(temp2)

Я хотел что-то, что потребовало бы два списка и могли делать то, что diff в bash делает. Поскольку этот вопрос впервые появляется, когда вы ищете «Python Diff два списка» и не очень специфичен, я опубликую то, с чем я придумал.

С использованием SequenceMather от difflib Вы можете сравнить два списка, как diff делает. Ни один из других ответов не скажет вам позицию, где возникает разница, но это делает. Некоторые ответы дают разницу только в одном направлении. Некоторые извлекивают элементы. Некоторые не обрабатывают дубликаты. Но это решение дает вам истинную разницу между двумя списками:

a = 'A quick fox jumps the lazy dog'.split()
b = 'A quick brown mouse jumps over the dog'.split()

from difflib import SequenceMatcher

for tag, i, j, k, l in SequenceMatcher(None, a, b).get_opcodes():
  if tag == 'equal': print('both have', a[i:j])
  if tag in ('delete', 'replace'): print('  1st has', a[i:j])
  if tag in ('insert', 'replace'): print('  2nd has', b[k:l])

Это выходы:

both have ['A', 'quick']
  1st has ['fox']
  2nd has ['brown', 'mouse']
both have ['jumps']
  2nd has ['over']
both have ['the']
  1st has ['lazy']
both have ['dog']

Конечно, если ваша заявка делает те же предположения, которые делают другие ответы, вы получите извлечь из них больше всего. Но если вы ищете верный diff Функциональность, то это единственный способ пойти.

Например, ни один из других ответов не может обрабатывать:

a = [1,2,3,4,5]
b = [5,4,3,2,1]

Но это делает:

  2nd has [5, 4, 3, 2]
both have [1]
  1st has [2, 3, 4, 5]

Попробуй это:

temp3 = set(temp1) - set(temp2)

Это может быть даже быстрее, чем список знаков:

list(itertools.filterfalse(set(temp2).__contains__, temp1))

Вот а Counter Ответ на самый простой случай.

Это короче, чем выше, которое делает двустороннюю дифференциров, потому что он только делает именно то, что спрашивает вопрос: генерируют список того, что в первом списке, но не второй.

from collections import Counter

lst1 = ['One', 'Two', 'Three', 'Four']
lst2 = ['One', 'Two']

c1 = Counter(lst1)
c2 = Counter(lst2)
diff = list((c1 - c2).elements())

В качестве альтернативы, в зависимости от ваших предпочтений читаемости, он делает для приличного одноклассника:

diff = list((Counter(lst1) - Counter(lst2)).elements())

Выход:

['Three', 'Four']

Обратите внимание, что вы можете удалить list(...) Звоните, если вы просто итерации по нему.

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

lst1 = ['One', 'Two', 'Two', 'Two', 'Three', 'Three', 'Four']
lst2 = ['One', 'Two']

Выход:

['Two', 'Two', 'Three', 'Three', 'Four']

Вы можете использовать наивный метод, если элементы диффигирования отсортированы и наборы.

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

print list1[len(list2):]

или с родным набором методов:

subset=set(list1).difference(list2)

print subset

import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print "Naive solution: ", timeit.timeit('temp1[len(temp2):]', init, number = 100000)
print "Native set solution: ", timeit.timeit('set(temp1).difference(temp2)', init, number = 100000)

Наивное решение: 0.0787101593292

Родной комплект Решение: 0.998837615564

Я немного поздно в игре для этого, но вы можете сделать сравнение производительности некоторых из вышеупомянутых кода с этим, два из самых быстрых претендентов,

list(set(x).symmetric_difference(set(y)))
list(set(x) ^ set(y))

Я прошу прощения за элементарный уровень кодирования.

import time
import random
from itertools import filterfalse

# 1 - performance (time taken)
# 2 - correctness (answer - 1,4,5,6)
# set performance
performance = 1
numberoftests = 7

def answer(x,y,z):
    if z == 0:
        start = time.clock()
        lists = (str(list(set(x)-set(y))+list(set(y)-set(y))))
        times = ("1 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 1:
        start = time.clock()
        lists = (str(list(set(x).symmetric_difference(set(y)))))
        times = ("2 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 2:
        start = time.clock()
        lists = (str(list(set(x) ^ set(y))))
        times = ("3 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 3:
        start = time.clock()
        lists = (filterfalse(set(y).__contains__, x))
        times = ("4 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 4:
        start = time.clock()
        lists = (tuple(set(x) - set(y)))
        times = ("5 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 5:
        start = time.clock()
        lists = ([tt for tt in x if tt not in y])
        times = ("6 = " + str(time.clock() - start))
        return (lists,times)

    else:    
        start = time.clock()
        Xarray = [iDa for iDa in x if iDa not in y]
        Yarray = [iDb for iDb in y if iDb not in x]
        lists = (str(Xarray + Yarray))
        times = ("7 = " + str(time.clock() - start))
        return (lists,times)

n = numberoftests

if performance == 2:
    a = [1,2,3,4,5]
    b = [3,2,6]
    for c in range(0,n):
        d = answer(a,b,c)
        print(d[0])

elif performance == 1:
    for tests in range(0,10):
        print("Test Number" + str(tests + 1))
        a = random.sample(range(1, 900000), 9999)
        b = random.sample(range(1, 900000), 9999)
        for c in range(0,n):
            #if c not in (1,4,5,6):
            d = answer(a,b,c)
            print(d[1])

Это еще одно решение:

def diff(a, b):
    xa = [i for i in set(a) if i not in b]
    xb = [i for i in set(b) if i not in a]
    return xa + xb

Если вы столкнетесь TypeError: unhashable type: 'list' вам нужно повернуть списки или наборы на кортежи, например,

set(map(tuple, list_of_lists1)).symmetric_difference(set(map(tuple, list_of_lists2)))

Смотрите также Как сравнить список списков / наборов в Python?

Вот несколько простых, Сохранение заказа Пути различия двух списков строк.

Код

Необычный подход, использующий pathlib:

import pathlib


temp1 = ["One", "Two", "Three", "Four"]
temp2 = ["One", "Two"]

p = pathlib.Path(*temp1)
r = p.relative_to(*temp2)
list(r.parts)
# ['Three', 'Four']

Это предполагает оба списка содержать строки с эквивалентными начинаниями. Увидеть документы Больше подробностей. Примечание, это не особенно быстро по сравнению с установленными операциями.


Прямая реализация, используя itertools.zip_longest:

import itertools as it


[x for x, y in it.zip_longest(temp1, temp2) if x != y]
# ['Three', 'Four']

Однострочная версия arulmr. решение

def diff(listA, listB):
    return set(listA) - set(listB) | set(listA) -set(listB)

Если вы хотите что-то большее, как смены ... Могли бы использовать счетчик

from collections import Counter

def diff(a, b):
  """ more verbose than needs to be, for clarity """
  ca, cb = Counter(a), Counter(b)
  to_add = cb - ca
  to_remove = ca - cb
  changes = Counter(to_add)
  changes.subtract(to_remove)
  return changes

lista = ['one', 'three', 'four', 'four', 'one']
listb = ['one', 'two', 'three']

In [127]: diff(lista, listb)
Out[127]: Counter({'two': 1, 'one': -1, 'four': -2})
# in order to go from lista to list b, you need to add a "two", remove a "one", and remove two "four"s

In [128]: diff(listb, lista)
Out[128]: Counter({'four': 2, 'one': 1, 'two': -1})
# in order to go from listb to lista, you must add two "four"s, add a "one", and remove a "two"

Мы можем рассчитать пересечение минус союз списков:

temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two', 'Five']

set(temp1+temp2)-(set(temp1)&set(temp2))

Out: set(['Four', 'Five', 'Three']) 

Это можно решить с одной строкой. Вопрос дан два списка (Temp1 и Temp2) возвращает их разницу в третьем списке (Temp3).

temp3 = list(set(temp1).difference(set(temp2)))

Скажем, у нас есть два списка

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

Из вышеупомянутых двух списков мы видим, что предметы 1, 3, 5 существуют в List2, а пункты 7, 9 нет. С другой стороны, предметы 1, 3, 5 существуют в List1, а пункты 2, 4 нет.

Какое лучшее решение вернуть новый список, содержащий элементы 7, 9 и 2, 4?

Все ответы выше находят решение, теперь что самое оптимальное?

def difference(list1, list2):
    new_list = []
    for i in list1:
        if i not in list2:
            new_list.append(i)

    for j in list2:
        if j not in list1:
            new_list.append(j)
    return new_list

против

def sym_diff(list1, list2):
    return list(set(list1).symmetric_difference(set(list2)))

Использование Timeit Мы можем увидеть результаты

t1 = timeit.Timer("difference(list1, list2)", "from __main__ import difference, 
list1, list2")
t2 = timeit.Timer("sym_diff(list1, list2)", "from __main__ import sym_diff, 
list1, list2")

print('Using two for loops', t1.timeit(number=100000), 'Milliseconds')
print('Using two for loops', t2.timeit(number=100000), 'Milliseconds')

возвращается

[7, 9, 2, 4]
Using two for loops 0.11572412995155901 Milliseconds
Using symmetric_difference 0.11285737506113946 Milliseconds

Process finished with exit code 0

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

>>> from sets import Set
>>>
>>> l1 = ['xvda', False, 'xvdbb', 12, 'xvdbc']
>>> l2 = ['xvda', 'xvdbb', 'xvdbc', 'xvdbd', None]
>>>
>>> Set(l1).symmetric_difference(Set(l2))
Set([False, 'xvdbd', None, 12])

Надеюсь, это будет полезно.

(list(set(a)-set(b))+list(set(b)-set(a)))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top