파이썬, 계산 목록 차이


195

파이썬에서 두 목록의 차이점을 계산하는 가장 좋은 방법은 무엇입니까?

A = [1,2,3,4]
B = [2,5]

A - B = [1,3,4]
B - A = [5]

답변:


206

set품목 주문이나 반복에 신경 쓰지 않는다면 사용하십시오 . 다음과 같은 경우 목록 이해를 사용하십시오 .

>>> def diff(first, second):
        second = set(second)
        return [item for item in first if item not in second]

>>> diff(A, B)
[1, 3, 4]
>>> diff(B, A)
[5]
>>> 

32
set(b)알고리즘이 Theta (n ^ 2) 대신 O (nlogn)인지 확인하는 것을 고려하십시오
Neil G

8
@Pencilcheck-A의 주문 또는 복제에 관심이있는 경우가 아닙니다. setB에 적용 하는 것은 무해하지만 A원본에 적용 하고 결과를 사용하는 A것은 아닙니다.
Mark Reed

1
@NeilG 세트 제작에 소요되는 시간을 고려하십니까? 필자의 경우 (두 목록에 약 10M 개의 문자열이 있음) 두 세트를 작성하고 빼는 시간은 하나의 세트를 작성하고 목록을 반복하는 것보다 상당히 큽니다.
dimril

@dimril 그것이 당신이하고 싶은 일이라면 더 정교한 것을 구현해야 할 것입니다. 예를 들어 두 목록을 O (n log n + m log m)로 정렬 한 다음 두 번째 목록을 반복하지만 이진 검색을 사용하여 첫 번째 목록에서 항목을 찾을 수 있습니다. O (n * n) 연산 대신 O (n log n + m log m + m log n) 연산으로 나올 것입니다. 바이너리 검색 구현에서 중복을 제거하기 위해 이웃을 확인하십시오. 이미 구현 한 패키지가있을 수도 있지만 확인하지는 않았습니다.
jaaq

366

순서가 중요하지 않은 경우 설정된 차이를 간단히 계산할 수 있습니다.

>>> set([1,2,3,4]) - set([2,5])
set([1, 4, 3])
>>> set([2,5]) - set([1,2,3,4])
set([5])

9
이것이 지금까지 가장 좋은 솔루션입니다. ~ 6000 개의 문자열이있는 목록의 테스트 사례는이 방법이 목록 이해보다 거의 100 배 빠르다는 것을 보여주었습니다.
perrygeo

15
신청에 따라 다름 : 주문 또는 복제 보존이 중요한 경우 Roman Bodnarchuk가 더 나은 접근 방식을 가질 수 있습니다. 속도와 순수한 세트와 같은 동작의 경우 더 좋습니다.
Bryan P

7
목록에 동일한 요소가 여러 개 있으면이 솔루션이 작동하지 않습니다.
karantan

목록 이해력보다 훨씬 낫습니다.
Dawei

4
이 솔루션은 매우 명백해 보이지만 잘못되었습니다. 죄송 해요. 물론 우리는리스트가 동일한 요소를 반복해서 가질 수 있음을 의미합니다. 그렇지 않으면 목록 차이가 아닌 세트 간의 차이에 대해 묻습니다.
sergzach

67

당신은 할 수 있습니다

list(set(A)-set(B))

list(set(B)-set(A))

7
그러나 A = [1,1,1]이고 B = [0]이면 [1]을 반환합니다.
Mark Bell

1
@Mark Bell : 세트가 고유 한 목록이기 때문입니다. (중복 제거)
흐린

1
@cloudy 그렇다면 이것은 질문에 대답하지 않습니다.
samm82

@ samm82 set (A)보다 A = [1,1,1]이 [1] 인 경우 set은 별개의 목록이므로 중복을 제거합니다. 따라서 A = [1,1,1]이고 B = [0]이면 [1]을 반환합니다.
흐린

29

짧막 한 농담:

diff = lambda l1,l2: [x for x in l1 if x not in l2]
diff(A,B)
diff(B,A)

또는:

diff = lambda l1,l2: filter(lambda x: x not in l2, l1)
diff(A,B)
diff(B,A)

14

Python 2.7.3 (기본값, 2014 년 2 월 27 일 19:58:35)-IPython 1.1.0-timeit : (github gist)

def diff(a, b):
  b = set(b)
  return [aa for aa in a if aa not in b]

def set_diff(a, b):
  return list(set(a) - set(b))

diff_lamb_hension = lambda l1,l2: [x for x in l1 if x not in l2]

diff_lamb_filter = lambda l1,l2: filter(lambda x: x not in l2, l1)

from difflib import SequenceMatcher
def squeezer(a, b):
  squeeze = SequenceMatcher(None, a, b)
  return reduce(lambda p,q: p+q, map(
    lambda t: squeeze.a[t[1]:t[2]],
      filter(lambda x:x[0]!='equal',
        squeeze.get_opcodes())))

결과 :

# Small
a = range(10)
b = range(10/2)

timeit[diff(a, b)]
100000 loops, best of 3: 1.97 µs per loop

timeit[set_diff(a, b)]
100000 loops, best of 3: 2.71 µs per loop

timeit[diff_lamb_hension(a, b)]
100000 loops, best of 3: 2.1 µs per loop

timeit[diff_lamb_filter(a, b)]
100000 loops, best of 3: 3.58 µs per loop

timeit[squeezer(a, b)]
10000 loops, best of 3: 36 µs per loop

# Medium
a = range(10**4)
b = range(10**4/2)

timeit[diff(a, b)]
1000 loops, best of 3: 1.17 ms per loop

timeit[set_diff(a, b)]
1000 loops, best of 3: 1.27 ms per loop

timeit[diff_lamb_hension(a, b)]
1 loops, best of 3: 736 ms per loop

timeit[diff_lamb_filter(a, b)]
1 loops, best of 3: 732 ms per loop

timeit[squeezer(a, b)]
100 loops, best of 3: 12.8 ms per loop

# Big
a = xrange(10**7)
b = xrange(10**7/2)

timeit[diff(a, b)]
1 loops, best of 3: 1.74 s per loop

timeit[set_diff(a, b)]
1 loops, best of 3: 2.57 s per loop

timeit[diff_lamb_filter(a, b)]
# too long to wait for

timeit[diff_lamb_filter(a, b)]
# too long to wait for

timeit[diff_lamb_filter(a, b)]
# TypeError: sequence index must be integer, not 'slice'

@ roman-bodnarchuk 목록 이해 함수 def diff (a, b) 가 더 빠른 것 같습니다.


14

위의 예는 차이를 계산하는 문제를 사소하게 만들었습니다. 정렬 또는 중복 제거를 가정하면 차이를 쉽게 계산할 수 있지만 비교에서 이러한 가정을 감당할 수없는 경우 diff 알고리즘을 간단하게 구현해야합니다. 파이썬 표준 라이브러리에서 difflib를 참조하십시오.

#! /usr/bin/python2
from difflib import SequenceMatcher

A = [1,2,3,4]
B = [2,5]

squeeze=SequenceMatcher( None, A, B )

print "A - B = [%s]"%( reduce( lambda p,q: p+q,
                               map( lambda t: squeeze.a[t[1]:t[2]],
                                    filter(lambda x:x[0]!='equal',
                                           squeeze.get_opcodes() ) ) ) )

산출:

A - B = [[1, 3, 4]]

1
내가 전에 보지 못한 difflib에 대해 +1을 얻습니다. 그럼에도 불구하고, 위의 답변이 명시된대로 문제 사소하게한다는 데 동의하지 않습니다 .
rbp

difflib를 사용해 주셔서 감사합니다. 표준 라이브러리를 사용하는 솔루션을 찾고있었습니다. 그러나, 이것은 파이썬 3에서 작업뿐만되지 않은 print함수에 명령의 변경, 및 reduce, filtermapunpythonic 선언했다. (그리고 나는 Guido가 옳을 지 모른다고 생각한다 -나는 또한 무엇을 이해하지 못한다 reduce.)
Post169

py3에 큰 변화가 없습니다. 필자는 필터에 대한 토론을 읽고, 맵을 줄이고, 축소하고 필터의 임플란트를 functools로 바꾸는 선택에 동의합니다. 파이썬의 혼합 기능, OO 및 절차 적 특성은 항상 IMO의 강점 중 하나였습니다.
Kevin

9
A = [1,2,3,4]
B = [2,5]

#A - B
x = list(set(A) - set(B))
#B - A 
y = list(set(B) - set(A))

print x
print y 


5

차이점이 재귀 적으로 목록의 항목에 깊이 들어가기를 원한다면 파이썬 패키지를 작성했습니다. https://github.com/erasmose/deepdiff

설치

PyPi에서 설치 :

pip install deepdiff

Python3 인 경우 다음도 설치해야합니다.

pip install future six

사용법 예

>>> from deepdiff import DeepDiff
>>> from pprint import pprint
>>> from __future__ import print_function

동일한 객체가 비어 있음

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

아이템 유형이 변경되었습니다

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:"2", 3:3}
>>> ddiff = DeepDiff(t1, t2)
>>> print (ddiff.changes)
    {'type_changes': ["root[2]: 2=<type 'int'> vs. 2=<type 'str'>"]}

아이템의 가치가 변경되었습니다

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:4, 3:3}
>>> ddiff = DeepDiff(t1, t2)
>>> print (ddiff.changes)
    {'values_changed': ['root[2]: 2 ====>> 4']}

아이템 추가 및 / 또는 제거

>>> 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.changes)
    {'dic_item_added': ['root[5, 6]'],
     'dic_item_removed': ['root[4]'],
     'values_changed': ['root[2]: 2 ====>> 4']}

문자열 차이

>>> 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.changes, indent = 2)
    { 'values_changed': [ 'root[2]: 2 ====>> 4',
                          "root[4]['b']:\n--- \n+++ \n@@ -1 +1 @@\n-world\n+world!"]}
>>>
>>> print (ddiff.changes['values_changed'][1])
    root[4]['b']:
    --- 
    +++ 
    @@ -1 +1 @@
    -world
    +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.changes, indent = 2)
    { 'values_changed': [ "root[4]['b']:\n--- \n+++ \n@@ -1,5 +1,4 @@\n-world!\n-Goodbye!\n+world\n 1\n 2\n End"]}
>>>
>>> print (ddiff.changes['values_changed'][0])
    root[4]['b']:
    --- 
    +++ 
    @@ -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.changes, indent = 2)
    { 'type_changes': [ "root[4]['b']: [1, 2, 3]=<type 'list'> vs. world\n\n\nEnd=<type 'str'>"]}

차이점

>>> 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, 2]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff.changes, indent = 2)
    { 'list_removed': ["root[4]['b']: [3]"]}

목록 차이 2 : 주문을 고려하지 않습니다.

>>> # Note that it DOES NOT take order into account
... 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]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff.changes, indent = 2)
    { }

사전이 포함 된 목록 :

>>> 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.changes, indent = 2)
    { 'dic_item_removed': ["root[4]['b'][2][2]"],
      'values_changed': ["root[4]['b'][2][1]: 1 ====>> 3"]}

5

가장 간단한 방법은

set ()을 사용하십시오 .difference (set ())

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

대답은 set([1])


2

사전 목록의 경우 set솔루션을 높이는 동안 전체 목록 이해 솔루션이 작동 합니다.

TypeError: unhashable type: 'dict'

테스트 사례

def diff(a, b):
    return [aa for aa in a if aa not in b]

d1 = {"a":1, "b":1}
d2 = {"a":2, "b":2}
d3 = {"a":3, "b":3}

>>> diff([d1, d2, d3], [d2, d3])
[{'a': 1, 'b': 1}]
>>> diff([d1, d2, d3], [d1])
[{'a': 2, 'b': 2}, {'a': 3, 'b': 3}]

0

원하는 경우 여러 항목과의 차이점을 제공하는 간단한 코드 :

a=[1,2,3,3,4]
b=[2,4]
tmp = copy.deepcopy(a)
for k in b:
    if k in tmp:
        tmp.remove(k)
print(tmp)

-1

TimeComplexity를 볼 때 의 를 최악의 경우 O (n)과 함께 작동합니다. 세트에서도 마찬가지입니다.

따라서 두 배열을 비교할 때 최상의 경우 TimeComplexity는 O (n)이고 최악의 경우 O (n ^ 2)입니다.

최상의 경우와 최악의 경우 O (n)과 함께 작동하는 대안 (그러나 불행히도 더 복잡한) 솔루션은 다음과 같습니다.

# Compares the difference of list a and b
# uses a callback function to compare items
def diff(a, b, callback):
  a_missing_in_b = []
  ai = 0
  bi = 0

  a = sorted(a, callback)
  b = sorted(b, callback)

  while (ai < len(a)) and (bi < len(b)):

    cmp = callback(a[ai], b[bi])
    if cmp < 0:
      a_missing_in_b.append(a[ai])
      ai += 1
    elif cmp > 0:
      # Item b is missing in a
      bi += 1
    else:
      # a and b intersecting on this item
      ai += 1
      bi += 1

  # if a and b are not of same length, we need to add the remaining items
  for ai in xrange(ai, len(a)):
    a_missing_in_b.append(a[ai])


  return a_missing_in_b

예 :

>>> a=[1,2,3]
>>> b=[2,4,6]
>>> diff(a, b, cmp)
[1, 3]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.