한 목록에서 발생하는 모든 요소를 다른 목록에서 제거합니다.
두 리스트가 가정해당 리스트가 있다.l1 ★★★★★★★★★★★★★★★★★」l2l1 - l2l1 없다l2.
순진한 루프 어프로치를 생각할 수 있습니다만, 이것은 매우 비효율적입니다.이것을 하는 비토닉적이고 효율적인 방법은 무엇입니까?
를 들어, 「」가 , 「」가 됩니다.l1 = [1,2,6,8] and l2 = [2,3,5,8],l1 - l2해야 한다[1,6]
Python은 List Compensions라는 언어 기능을 가지고 있으며, 이러한 기능을 매우 쉽게 만들 수 있습니다.다음 문장은 사용자가 원하는 대로 수행하며 결과를 저장합니다.l3:
l3 = [x for x in l1 if x not in l2]
l3 will will 。[1, 6].
한 가지 방법은 세트를 사용하는 것입니다.
>>> set([1,2,6,8]) - set([2,3,5,8])
set([1, 6])
단, 이러한 세트는 요소의 순서를 유지하지 않으며 중복된 요소가 제거되는 원인이 됩니다.요소도 해시 가능해야 합니다.이러한 제한을 견딜 수 있는 경우, 이것이 가장 단순하고 최고의 퍼포먼스 옵션인 경우가 많습니다.
퍼포먼스 비교
Python 3.9.1과 Python 2.7.16에서 언급된 모든 답변의 성능을 비교합니다.
파이썬 3.9.1
답변은 퍼포먼스 순으로 기재되어 있습니다.
뺄셈 "-" 연산을 사용한 Arku의 차이 - (루프당 91.3nsec)
mquadri$ python3 -m timeit -s "l1 = set([1,2,6,8]); l2 = set([2,3,5,8]);" "l1 - l2" 5000000 loops, best of 5: 91.3 nsec per loopMoinuddin Quadri 사용 - (루프당 133 nsec)
mquadri$ python3 -m timeit -s "l1 = set([1,2,6,8]); l2 = set([2,3,5,8]);" "l1.difference(l2)" 2000000 loops, best of 5: 133 nsec per loopMoinuddin Quadri의 목록 이해(루프당 366밀리초)
mquadri$ python3 -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 5: 366 nsec per loop플레인 리스트의 도넛 리스트 이해 - (루프당 489 nsec)
mquadri$ python3 -m timeit -s "l1 = [1,2,6,8]; l2 = [2,3,5,8];" "[x for x in l1 if x not in l2]" 500000 loops, best of 5: 489 nsec per loopDaniel Pryden의 생성기 표현식 기반 검색 및 유형 캐스팅을 통해
list- (루프당 583 nsec) : 목록으로 명시적으로 type-casting하여 최종 객체를 가져옵니다.list(OP의 요구대로).생성기 식을 목록 이해로 대체하면, Moinuddin Quadri의 목록 이해와 기반 룩업과 같아집니다.mquadri$ mquadri$ python3 -m timeit -s "l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "list(x for x in l1 if x not in l2)" 500000 loops, best of 5: 583 nsec per loopMoinuddin Quadri's를 사용하여 명시적으로 타이핑하여
list(Python 3.x에서와 같이 명시적으로 type-cast를 실행해야 합니다.반복자를 반환한다) - (루프당 681 nsec)mquadri$ python3 -m timeit -s "l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "list(filter(lambda x: x not in l2, l1))" 500000 loops, best of 5: 681 nsec per loopAkshay Hazari's는 + - (루프당 3.36usec)의 조합을 사용합니다. : 명시적으로 Type-Casting to
listPython 3.x 。 수입도 되고요.functoolsreducexPython 3.x 경 xmquadri$ python3 -m timeit "from functools import reduce; l1 = [1,2,6,8]; l2 = [2,3,5,8];" "list(reduce(lambda x,y : filter(lambda z: z!=y,x) ,l1,l2))" 100000 loops, best of 5: 3.36 usec per loop
파이썬 2.7.16
답변은 퍼포먼스 순으로 기재되어 있습니다.
뺄셈 "-" 연산을 사용한 Arku의 차이 - (루프당 0.0783usec)
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.0783 usec per loopMoinuddin Quadri 사용 - (루프당 0.117usec)
mquadri$ mquadri$ python -m timeit -s "l1 = set([1,2,6,8]); l2 = set([2,3,5,8]);" "l1.difference(l2)" 10000000 loops, best of 3: 0.117 usec per loopMoinuddin Quadri의 목록 이해와 기반 룩업 (루프당 0.246usec)
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.246 usec per loop플레인 리스트의 도넛 리스트 이해 - (루프당 0.372usec)
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.372 usec per loopMoinuddin Quadri 사용 - (루프당 0.593usec)
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.593 usec per loopDaniel Pryden의 생성기 표현식 기반 검색 및 유형 캐스팅을 통해
list- (루프당 0.964): 목록으로 명시적으로 타이핑하여 최종 객체를 가져옵니다.list(OP의 요구대로).생성기 식을 목록 이해로 대체하면, Moinuddin Quadri의 목록 이해와 기반 룩업과 같아집니다.mquadri$ python -m timeit -s "l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "list(x for x in l1 if x not in l2)" 1000000 loops, best of 3: 0.964 usec per loopAkshay Hazari's는 + - (루프당 2.78usec)의 조합을 사용합니다.
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: 2.78 usec per loop
자세히 이해하고, 그리고 수 .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
l2}에서 x에 대해 {x for x for x in l2} 또는 set(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])
「」를 사용합니다.filterfalse 람다 이온 없이
또는 이와 유사한 기능을 사용할 경우 일반적으로 다음을 방지하여 성능을 절감할 수 있습니다.lambda- 기존 - 기존 기능을 사용합니다.의 list ★★★★★★★★★★★★★★★★★」set에, 격납용기 체크에 사용하는 -containment를 정의합니다.그in - 를 사용합니다.x in l2할 수 l2.__contains__(x). 이 이 더 , 이 에는 더 나은 수 상, 환, 우, 우, 했, 했, 했, 했, 했, 했, 했, 했, 했, 했, 했, 했, 했, 했, 했, ., ., ., ., ., ., ., ., ., ., ., a, a, a, a, a, a, a, a, a, a, a, a, a,lambda하는 경우, 「」는 「-」와 조합해 사용합니다.filterfalse:
>>> from itertools import filterfalse
>>> l1 = [1, 2, 6, 8]
>>> l2 = [2, 3, 5, 8]
>>> list(filterfalse(l2.__contains__, l1))
[1, 6]
filterfalse는, 「반복」을 반환하는 합니다.false의 l2.__contains__.
속도가 .__contains__은 다음과 같습니다.
>>> from itertools import filterfalse
>>> l1 = [1, 2, 6, 8]
>>> l2 = set([2, 3, 5, 8])
>>> list(filterfalse(l2.__contains__, l1))
[1, 6]
성능
목록 사용:
$ python3 -m timeit -s "from itertools import filterfalse; l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "list(filterfalse(l2.__contains__, l1))"
500000 loops, best of 5: 522 nsec per loop
세트 사용:
$ python3 -m timeit -s "from itertools import filterfalse; l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "list(filterfalse(l2.__contains__, l1))"
1000000 loops, best of 5: 359 nsec per loop
「」를 사용합니다.set.difference():
를 사용하여 다른 요소에 없는 집합의 요소를 사용하여 새 집합을 가져올 수 있습니다.set(A).difference(B)다음 항목에 포함된 세트로 반환됩니다.A ,,, , ,, 단, 에, 에 , , ,.B §:
>>> set([1,2,6,8]).difference([2,3,5,8])
{1, 6}
Arku의 답변에서 언급된 차이를 얻기 위한 함수적 접근법입니다(집합 차이에 산술적 감산 연산자를 사용).
세트가 순서가 맞지 않기 때문에 초기 리스트에서 요소의 순서가 느슨해집니다.(요소의 순서를 유지하려면 다음 항을 읽는 것이 좋습니다.)
에서의 리스트 이해 사용set 룩업
초기 목록에서 순서를 유지하려면 도넛의 목록 이해 기반 답변이 효과적입니다.그러나 내부적으로 를 사용하여 다른 목록에 요소가 있는지 여부를 확인함으로써 승인된 답변에서 더 나은 성능을 얻을 수 있습니다.예를 들어 다음과 같습니다.
l1, l2 = [1,2,6,8], [2,3,5,8]
s2 = set(l2) # Type-cast `l2` to `set`
l3 = [x for x in l1 if x not in s2]
# ^ Doing membership checking on `set` s2
더를 알고 '멤버십 체크'를 클릭해 주세요.set★★★★★★★★★와 비교하면list, 다음을 읽어주세요.목록보다 세트를 더 빨리 만드는 이유는 무엇입니까?
「」를 사용합니다.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]
Python 3.8에서 목록 이해 벤치마크 설정
(Moinuddin Quadri 벤치마크 추가)
tldr: Arku의 솔루션을 사용하면 약속보다 훨씬 빠릅니다!
목록과 비교하여 기존 파일 확인
이 예에서는 리스트와 기존 파일명을 대조하는 실제 어플리케이션에서는 Arku의 세트솔루션을 사용하는 것이 피토닉리스트 이해보다 40배(!) 빠릅니다.
목록 이해:
%%time
import glob
existing = [int(os.path.basename(x).split(".")[0]) for x in glob.glob("*.txt")]
wanted = list(range(1, 100000))
[i for i in wanted if i not in existing]
벽면 시간: 28.2초
놓다
%%time
import glob
existing = [int(os.path.basename(x).split(".")[0]) for x in glob.glob("*.txt")]
wanted = list(range(1, 100000))
set(wanted) - set(existing)
벽면 시간: 689 밀리초
이것을 시험해 보세요.
l1=[1,2,6,8]
l2=[2,3,5,8]
r=[]
for x in l1:
if x in l2:
continue
r=r+[x]
print(r)
dicts의 순서 속성을 이용하여 순서 유지(Python 3.7+)
<고객명> 님의 : <고객명>dictsPython 3.6에서는 삽입 순서대로 키를 유지하지만 사양에 의해 보장되지는 않습니다.에서는 이 되었습니다.3.7 이이 was 。
의 키dict의 기능을 set; 중복은 암묵적으로 필터링되며 해시에 의해 룩업이 효율적입니다. 때문에 dict를 dict로 해서 set할 수 .l1(Keys)], [키(Keys)], [키(Keys)]에 합니다.l2이렇게 하면 순서가 유지되고 고속 알고리즘이 사용되지만 상당한 양의 고정 요소 오버헤드가 발생합니다.
d = dict.fromkeys(l1)
for i in l2:
try:
del d[i]
except KeyError:
pass
l3 = list(d.keys())
만약 당신이 그 행동을 원한다면, 설정된 접근법이 가장 좋다.l2에 한 번만 존재하는 목록 l1의 모든 요소의 인스턴스를 제거하지 않으면 이러한 집합 작업이 잘못된 결과로 이어집니다.l1 및 l2에 반복 요소가 있으며 나머지 요소의 순서를 유지하면서 l1 ~l2의 2개의 리스트가 실제로 다르다고 가정합니다.
l1 = [1, 2, 3, 4, 5, 5, 6, 5, 5, 2]
l2 = [1, 2, 2, 5]
_ = [l1.remove(item) for item in l2 if item in l1] # discard return value
print(l1) # [3, 4, 5, 6, 5, 5]
- 이 작업은 설정 작업보다 훨씬 느리므로 사용 사례에 필요한 경우에만 사용하십시오.
- 원래 목록을 수정하지 않으려면 먼저 목록의 복사본을 만드십시오.
언급URL : https://stackoverflow.com/questions/4211209/remove-all-the-elements-that-occur-in-one-list-from-another
'source' 카테고리의 다른 글
| 배열에 대한 라라벨 컬렉션 (0) | 2022.12.12 |
|---|---|
| Javascript의 파일 이름 문자열에서 확장자를 추출하는 방법은 무엇입니까? (0) | 2022.12.12 |
| POST 파라미터를 Postman으로 송신하는 것은 동작하지 않지만 GET 파라미터를 송신하는 것은 동작합니다. (0) | 2022.12.12 |
| AngularJs ng-repeat 핸들 빈 목록 대소문자 (0) | 2022.12.12 |
| '가 뭐죠?'가 뭐죠?무엇인가.무엇인가.정확히요?정확히요?의 줄임말이다의 줄임말이다..5.4.0부터 디폴트로 유효하게 되어 있습니다.5.4.0부터 디폴트로 유효하게 되어 있습니다.설정을 지정합.. (0) | 2022.12.12 |