2017-03-05 6 views
1

그래서 두 개의 int리스트 xs와 ys (임의의 길이)가 있고 각리스트에 나타나는 중복을 효율적으로 제거하고 싶습니다. 당신은/그것을 통해 당신과 같이 루프를 목록을 편집해야 할 수 없기 때문에, 내 시도했다 : 값이 XS에 있지만 한 번 YS에 두 번 등장파이썬에서 두리스트의 일치 항목을 찾아서 제거합니다.

matches = [match for match in xs if match in ys] 
for match in matches: 
    xs.remove(match) 
    ys.remove(match) 

그러나 중요한 경우,이 때문에 오류를 얻을 수 "ys에 일치하는 경우"는 동일한 값에 대해 두 번 true로 평가되지만, 한 번만 계산하면됩니다. 다음 8 개 필요

xs = [0, 2, 4, 8, 8, 100] 
ys = [1, 3, 5, 8, 8, 8, 10] 

이 두 목록에서 두 번 제거 할 다음과 같은 경우

그래서, 명확하게.

어떻게 효율적으로 수행 할 수 있습니까? 감사합니다

편집 : 목록 반드시 필요하지 않으며 실제로 두 목록에 중복이 포함될 가능성이 있습니다.

답변

4

교차로에 멀티 세트 (collections.Counter)를 사용할 수 있습니다. 많은 수의 중복이 예상되고 목록이 크다면 비싸기 때문에 .remove을 피하는 것이 좋습니다. 목록 이해력은 훨씬 더 잘 확장됩니다. 우리는 중재 된 itertools 속임수를 사용하여 표시된 중복을 필터링합니다. 등이 비로소 작동 당신의 요소가 해쉬 경우 것으로

from collections import Counter 
from itertools import repeat, chain 

xc = Counter(xs) 
yc = Counter(ys) 
matches = xc & yc 
tr = repeat(True) 
rm = {k: chain(repeat(False, m), tr) for k, m in matches.items()} 
xs = [x for x in xs if not x in rm or next(rm[x])] 
rm = {k: chain(repeat(False, m), tr) for k, m in matches.items()} 
ys = [y for y in ys if not y in rm or next(rm[y])] 

주 마지막 발생 첫 대신을 제거하지 예를 들어,이 적응 될 수 있음을 유의하시기 바랍니다.

+1

그것은 2 개의 복제본에서만 작동하지만 n 복제본에서는 그렇지 않다는 것을 보여주기 위해 예제를 업데이트했습니다. –

+0

@BenJones 아하겠습니다. 명확히 해 주시겠습니까? 이 상황에서 일어날 일은 :'xs = [1,1,1,1,2]''ys = [1,1,3]'? 원하는 출력? 'xs = [1,1,1,2]''ys = [1,3']? 또는'xs = [1,1,2]''ys = [3]'또는'xs = [1,2]''ys = [3]'? –

+0

두 목록에 공통적 인 두 개의 1이 있으므로 원하는 출력은 xs = [1,1,2] 및 ys = [3]입니다. 혼란스러워서 죄송합니다! –