파이썬은 다른 목록에없는 하나의 목록에서 요소를 찾습니다 [중복]


136

한 목록에는 있지만 다른 목록에는없는 특정 요소의 새 목록을 만들려면 두 목록을 비교해야합니다. 예를 들면 :

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

list_1을 반복하고 list_1에없는 list_2의 모든 요소를 ​​main_list에 추가하고 싶습니다.

결과는 다음과 같아야합니다.

main_list=["f", "m"]

파이썬으로 어떻게 할 수 있습니까?


2
list_2어디에도 나타나지 않는의 list_1요소 또는 list_2의 동일한 색인에 없는 요소를 찾고 list_1있습니까?
Patrick Haugh

답변:


98

요약 :
솔루션 (1)

import numpy as np
main_list = np.setdiff1d(list_2,list_1)
# yields the elements in `list_2` that are NOT in `list_1`

해결책 (2) 정렬 된 목록을 원합니다

def setdiff_sorted(array1,array2,assume_unique=False):
    ans = np.setdiff1d(array1,array2,assume_unique).tolist()
    if assume_unique:
        return sorted(ans)
    return ans
main_list = setdiff_sorted(list_2,list_1)




설명은 :
(1) 당신은 NumPy와의를 사용할 수 있습니다 setdiff1d( array1, array2, assume_unique= False).

assume_unique배열이 이미 고유한지 여부를 사용자에게 묻습니다.
인 경우 False고유 요소가 먼저 결정됩니다.
이면 True함수는 요소가 이미 고유하다고 가정하고 함수는 고유 요소 결정을 건너 뜁니다.

이러한 수율 고유 한 값 array1이이 없습니다array2. assume_unique이다 False기본적으로.

고유 한 요소 ( Chinny84응답을 기반으로 함)에 관심이 있다면 간단히 (여기서 assume_unique=False=> 기본값)을 사용하십시오.

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)
# yields the elements in `list_2` that are NOT in `list_1`


(2) 답변을 정렬하고 싶은 분들을 위해 커스텀 함수를 만들었습니다.

import numpy as np
def setdiff_sorted(array1,array2,assume_unique=False):
    ans = np.setdiff1d(array1,array2,assume_unique).tolist()
    if assume_unique:
        return sorted(ans)
    return ans

답을 얻으려면 다음을 실행하십시오.

main_list = setdiff_sorted(list_2,list_1)

참고 사항 :
(a) 솔루션 2 (사용자 지정 함수 setdiff_sorted)는 목록을 반환 합니다 ( 솔루션 1 의 배열 과 비교 ).

(b) 요소가 고유한지 확실하지 않은 경우 setdiff1d솔루션 A와 B 모두에서 NumPy의 기본 설정을 사용하십시오 . 합병증의 예는 무엇입니까? 참고 (c)를 참조하십시오.

(c) 두 목록 중 하나가 고유 하지 않으면 상황이 달라집니다 . 고유하지 않은
list_2: list2 = ["a", "f", "c", "m", "m"]. 있는 그대로 유지 list1: 수율 list_1 = ["a", "b", "c", "d", "e"]
기본값 설정 (두 솔루션 모두). 그러나을 설정 하면 두 솔루션 모두 . 왜? 이는 사용자가 요소가 고유하다고 가정했기 때문입니다.) 따라서 유지하는 것이 좋습니다assume_unique["f", "m"]assume_unique=True["f", "m", "m"]assume_unique기본값으로. 두 답변이 모두 정렬되어 있습니다.


목록이 이미 주문 된 경우 주문한 목록도 반환됩니다. 집합으로 변환 한 다음 차이를 얻는 기본 솔루션 (아래에 표시된 솔루션)은 정렬되지 않은 목록을 반환하므로 결과를 시각적으로 검사하기가 더 어려워 질 수 있습니다.
Doubledown

1
안녕하세요, @Doubledown! 귀하의 우려는 수정 된 게시물에서 해결되었습니다. 도움이 되었기를 바랍니다!
jcoderepo

183

세트를 사용할 수 있습니다.

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']

@JonClements의 의견에 따라 다음은 더 깔끔한 버전입니다.

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

2
이것은 우리가 unique요소 에만 신경을 m's쓰면 좋지만 예를 들어 여러 개가 있으면 선택하지 않을 것입니다.
Chinny84 dec.

사실입니다. 포스터가 독특한 요소를 찾고 있다고 생각했습니다. 나는 그것이 그가 "특정"의 의미에 달려 있다고 생각한다.
nrlakin

실제로 추신 : 특히 명확하지 않은 원래 질문에 대해 귀하의 답변에 대해 투표하지 않았습니다.
Chinny84

13
당신이 쓸 수 list(set(list_2).difference(list_1))명시 적으로 피할 수있는 set... 변환
존 클레멘트

걱정 마! 형식 지정 지원에 대해 @leaf에게 감사드립니다.
nrlakin

61

네이티브 메서드를 사용할 수있을 때 위의 설명이 왜 그렇게 복잡한 지 잘 모르겠습니다.

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

6
순서를 보존하는 것이 이유
Keith

57

다음 과 같이 목록 이해력을 사용하십시오 .

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']

편집하다:

아래 주석에서 언급했듯이 큰 목록으로 위의 방법은 이상적인 솔루션이 아닙니다. 이 경우 더 나은 옵션은 첫 번째 로 변환 list_1하는 것입니다 set.

set_1 = set(list_1)  # this reduces the lookup time from O(n) to O(1)
main_list = [item for item in list_2 if item not in set_1]

3
참고 : 큰를 들어 list_1, 당신이에 preconvert 싶어 set/ frozenset, 예를 들어 set_1 = frozenset(list_1), 다음 main_list = [item for item in list_2 if item not in set_1]에서 확인 시간 감소 O(n)(약)에 항목 당을 O(1).
ShadowRanger dec.

@ettanany ettanany가 게시 한대로 솔루션을 시도하는 경우주의하십시오. 나는 ettanany의 솔루션을있는 그대로 시도했으며 실제로 더 큰 목록의 경우 매우 느립니다. 섀도우 레인저의 제안을 반영하기 위해 답변을 업데이트 할 수 있습니까?
Doubledown

문자열 대신 색인을 얻을 수 있습니까?
JareBear

@JareBear 당신은 그것을 enumerate()위해 사용할 수 있습니다 :[index for (index, item) in enumerate(list_2) if item not in list_1]
ettanany

@ettanany 님 감사합니다 !! 최대한 빨리 구현할 것입니다. 하지만 코드가 훨씬 깔끔해 보입니다.
JareBear

5

당신은 단지 필요로하는 한 줄 용액 (수입 무시)하려면 O(max(n, m))길이의 입력에 대한 작업을 n하고 m,하지 O(n * m)작업을, 당신은에 그렇게 할 수 모듈 :itertools

from itertools import filterfalse

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

이는 생성시 콜백 함수를 사용하는 기능적 함수를 활용하여 콜백을 한 번 생성하고 어딘가에 저장할 필요없이 모든 요소에 대해 재사용 할 수 있도록합니다 ( 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), 임시 s 또는 s 를 포함하지 않는 패트릭의 대답 을 선택해야합니다 ( s가 대략 인 경우에도 간단한 동등성 검사보다 검사 당 더 높은 "상수"계수를가집니다. ) 및 작업이 다른 어떤 대답보다 적으며 문제가 위치에 민감한 경우 일치하는 요소가 일치하지 않는 오프셋에 나타날 때 유일한 올바른 해결책입니다.listsetsetO(1)O(min(n, m))

† : 한 줄로 된 목록 이해력으로 동일한 작업을 수행하는 방법은 중첩 된 루프를 남용하여 "가장 바깥 쪽"루프에서 값을 만들고 캐시하는 것입니다. 예 :

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에서 클로저를 사용하지 않기 때문에 list comprehensions; 그들은 그들이 사용되는 것과 같은 범위에서 작동합니다).


4
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']

마찬가지로 동등한 지능형리스트 기반의 솔루션 경우,이 느려집니다 list_1크고, list_2적지 않은 크기입니다 그것을 포함하기 때문에, len(list_2) O(n)스캔을 list_1그것을 만드는, O(n * m)(여기서 nm의 길이 있습니다 list_2list_1각각이). 당신이 변환하면 list_1A를 set/ frozenset앞까지의 수표가 수행 할 수 있습니다 포함 O(1)총 작업하고, O(n)의 길이를 list_2(기술적으로 O(max(n, m)), 당신은 할 수 있기 때문에 O(m)을 만들기 위해 작업을 set).
ShadowRanger

1

나는 zip목록을 함께 요소별로 비교할 것입니다.

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

영업 이익은 요소에 의해 요소를 비교하기 위해서는이이 (가 불분명 예제 어느 길을 갈 수있다) 많이 는 모두 이상 단일 싼 통과 이후,보다 효율적인 다른 답변보다 list하나의 새와의 list건설되고, 추가 임시직은 등 고가의 수납 확인하지
ShadowRanger

1
@ShadowRanger 이것은 핵심 요소 인 요소 별 차이에서만 작동합니다
ford prefect

@fordprefect : 네. 내 대답 은 위치 독립적 인 차이점을 다룹니다.
ShadowRanger 2017 년

1

두 가지 방법을 사용했고 한 가지 방법이 다른 방법보다 유용하다는 것을 알았습니다. 내 대답은 다음과 같습니다.

내 입력 데이터 :

crkmod_mpp = ['M13','M18','M19','M24']
testmod_mpp = ['M13','M14','M15','M16','M17','M18','M19','M20','M21','M22','M23','M24']

방법 1 : np.setdiff1d위치를 유지하기 때문에 다른 방법보다이 방법을 좋아합니다.

test= list(np.setdiff1d(testmod_mpp,crkmod_mpp))
print(test)
['M15', 'M16', 'M22', 'M23', 'M20', 'M14', 'M17', 'M21']

방법 2 : 방법 1과 같은 답을 주지만 순서를 어지럽 힙니다.

test = list(set(testmod_mpp).difference(set(crkmod_mpp)))
print(test)
['POA23', 'POA15', 'POA17', 'POA16', 'POA22', 'POA18', 'POA24', 'POA21']

Method1은 np.setdiff1d내 요구 사항을 완벽하게 충족합니다. 정보에 대한 답변입니다.


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

ser1에서 ser2에있는 항목을 제거합니다.

입력

ser1 = pd.Series ([1, 2, 3, 4, 5]) ser2 = pd.Series ([4, 5, 6, 7, 8])

해결책

ser1 [~ ser1.isin (ser2)]


Stack Overflow에 오신 것을 환영합니다. 이 질문에는 8 개의 다른 답변이 있으며 그 중 하나는 원본 포스터가 수락했습니다. 귀하의 답변이 이미 제시된 내용을 어떻게 개선하는지 설명해주십시오.
chb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.