[python] 한 목록에서 발생하는 모든 요소를 ​​다른 목록에서 제거

하자 내가 두 개의 목록이 말을 l1하고 l2. in의 l1 - l2모든 요소를 ​​반환하는 을 수행하고 싶습니다 .l1l2

이 작업을 수행하는 순진한 루프 접근 방식을 생각할 수 있지만 실제로는 비효율적입니다. 이것을하는 pythonic하고 효과적인 방법은 무엇입니까?

예를 들어, 내가 가지고있는 경우 l1 = [1,2,6,8] and l2 = [2,3,5,8], l1 - l2반환해야[1,6]



답변

파이썬에는 List Comprehensions 라는 언어 기능 이있어 이러한 종류의 작업을 매우 쉽게 수행 할 수 있습니다. 다음 문장은 원하는 것을 정확하게 수행하고 결과를 저장합니다 l3.

l3 = [x for x in l1 if x not in l2]

l3포함합니다 [1, 6].


답변

한 가지 방법은 세트를 사용하는 것입니다.

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


답변

대안으로 원하는 결과를 얻기 위해 람다 식과 함께 사용할filter 수도 있습니다. 예를 들면 다음과 같습니다.

>>> l1 = [1,2,6,8]
>>> l2 = set([2,3,5,8])

#     v  `filter` returns the a iterator object. Here I'm type-casting 
#     v  it to `list` in order to display the resultant value
>>> list(filter(lambda x: x not in l2, l1))
[1, 6]

성능 비교

여기에 언급 된 모든 답변의 성능을 비교하고 있습니다. 예상대로 Arkku의 set 기본 작업은 가장 빠릅니다.

  • Arkku의 Set Difference -First (루프 당 0.124 usec)

    mquadri$ python -m timeit -s "l1 = set([1,2,6,8]); l2 = set([2,3,5,8]);" "l1 - l2"
    10000000 loops, best of 3: 0.124 usec per loop
  • set조회를 통한 Daniel Pryden의 목록 이해 -초 (루프 당 0.302 usec)

    mquadri$ python -m timeit -s "l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "[x for x in l1 if x not in l2]"
    1000000 loops, best of 3: 0.302 usec per loop
  • 일반 목록에 대한 도넛의 목록 이해 -세 번째 (루프 당 0.552 usec)

    mquadri$ python -m timeit -s "l1 = [1,2,6,8]; l2 = [2,3,5,8];" "[x for x in l1 if x not in l2]"
    1000000 loops, best of 3: 0.552 usec per loop
  • Moinuddin Quadri를 사용하여filter -네 번째 (루프 당 0.972 usec)

    mquadri$ python -m timeit -s "l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "filter(lambda x: x not in l2, l1)"
    1000000 loops, best of 3: 0.972 usec per loop
  • 의하기 Akshay Hazari의 사용 조합 reduce+filter – 다섯 번째 (루프 당 3.97 마이크로 초)

    mquadri$ python -m timeit "l1 = [1,2,6,8]; l2 = [2,3,5,8];" "reduce(lambda x,y : filter(lambda z: z!=y,x) ,l1,l2)"
    100000 loops, best of 3: 3.97 usec per loop

추신 : set 순서를 유지하지 않고 목록에서 중복 요소를 제거합니다. 따라서 필요한 경우 설정된 차이를 사용하지 마십시오 .


답변

여기에서 Donut의 답변과 다른 답변을 확장하면 목록 이해 대신 생성기 이해를 사용하고 set데이터 구조 를 사용하여 더 나은 결과를 얻을 수 있습니다 ( in연산자는 목록에서 O (n)이지만 O (1) 이므로 세트에).

다음은 귀하에게 적합한 기능입니다.

def filter_list(full_list, excludes):
    s = set(excludes)
    return (x for x in full_list if x not in s)

결과는 필터링 된 목록을 느리게 가져 오는 반복 가능합니다. 실제 목록 객체가 필요한 경우 (예 : len()결과에 대해 수행해야하는 경우 ) 다음과 같이 목록을 쉽게 작성할 수 있습니다.

filtered_list = list(filter_list(full_list, excludes))


답변

Python 세트 유형을 사용하십시오. 그것은 가장 파이썬적인 것입니다. 🙂

또한 네이티브이기 때문에 가장 최적화 된 방법이어야합니다.

보다:

http://docs.python.org/library/stdtypes.html#set

http://docs.python.org/library/sets.htm (이전 파이썬의 경우)

# Using Python 2.7 set literal format.
# Otherwise, use: l1 = set([1,2,6,8])
#
l1 = {1,2,6,8}
l2 = {2,3,5,8}
l3 = l1 - l2


답변

사용 설정 함축 {x의 X의 L2} 또는 세트 (L2)의 세트를 얻기 위해, 다음 사용 목록 함축을 목록을 얻으려면

l2set = set(l2)
l3 = [x for x in l1 if x not in l2set]

벤치 마크 테스트 코드 :

import time

l1 = list(range(1000*10 * 3))
l2 = list(range(1000*10 * 2))

l2set = {x for x in l2}

tic = time.time()
l3 = [x for x in l1 if x not in l2set]
toc = time.time()
diffset = toc-tic
print(diffset)

tic = time.time()
l3 = [x for x in l1 if x not in l2]
toc = time.time()
difflist = toc-tic
print(difflist)

print("speedup %fx"%(difflist/diffset))

벤치 마크 테스트 결과 :

0.0015058517456054688
3.968189239501953
speedup 2635.179227x    


답변

대체 솔루션 :

reduce(lambda x,y : filter(lambda z: z!=y,x) ,[2,3,5,8],[1,2,6,8])