2012-03-28 3 views
4

나는 아마존 보토와 함께 일하고 있고 나는 2 개의 목록을 가지고있다. 목록 1에는 인스턴스 개체가 포함되어 있습니다. 목록 2는 InstanceInfo 객체를 포함합니다. 두 객체 모두 id라는 속성을 가지고 있습니다. 나는 InstanceInfo 목록에 존재하는 Instance 객체 목록을 가져와야한다.개체 집합과 파이썬 세트 교집합

l1 = [Instance:i-04072534, Instance:i-06072536, Instance:i-08072538, Instance:i-0a07253a, Instance:i-e68fa1d6, Instance:i-e88fa1d8, Instance:i-ea8fa1da, Instance:i-ec8fa1dc] 

l2 = [InstanceInfo:i-ec8fa1dc, InstanceInfo:i-ea8fa1da, InstanceInfo:i-e88fa1d8, InstanceInfo:i-e68fa1d6] 

구인 결과 :

l3 = [Instance:i-ec8fa1dc, Instance:i-ea8fa1da, Instance:i-e88fa1d8, Instance:i-e68fa1d6] 

지금은 그것을 통해 작업이 :

l3= [] 
for a in l1 
    for b in l2: 
     if a.id == b.id: 
      l3.append(a) 

그러나, 나는 나는이 사용 교집합을 교체해야한다고 들었습니다. 나는 예제를보고 있으며 매우 직관적으로 보입니다. 그러나 나는 객체에 대한 예제를 보지 못했다.

나는 약간 놀아 왔고 이론적으로는 제대로 작동하는 것을 볼 수 있지만 아직 모르는 경우가있는 '고급'구문이있을 수 있습니다. 나는 아직도 파이썬을 배우고있다.

답변

7

는 (유사하면서) 마르신의 대답보다 더 빨리 뭔가 :

ids_l1 = set(x.id for x in l1) # All ids in list 1 
intersection = [item for item in l2 if item.id in ids_l1] # Only those elements of l2 with an id in l1 

그것은하는 것이 중요하다 ids_l1 미리 계산하고 세트가 전체로서 (각 시간을 재구성 할 것 같은 if item.id in set(…)를 작성하지 않는 테스트 표현식은 각 요소 item에 대해 재평가됩니다.

파이썬 세트는 빠른 요소 구성원 테스트 (in)를 제공합니다. 이러한 테스트는 목록보다 집합을 사용하는 것이 훨씬 빠릅니다 (목록의 요소는 하나씩 읽어야하지만 집합의 요소는 "해시"여야 함).

+0

여기에서 당신은 맞습니다. 왜냐하면 교차가 목록 생성에서 벗어 났기 때문입니다. 그러나 Marcin의 솔루션은 가장 느립니다. –

+0

@ MateuszWoźniak 여러분의 해결책이 가장 느릴 것이라는 데는 의심의 여지가 없으며, 당신의 이데온은 단순히 "결과 : 실행되지 않음"을 말합니다. 보통은'timeit' 라이브러리를 사용하지 않는다는 것을 감안할 때 아마도 가장 좋을 것입니다. 시스템 시간. – Marcin

+0

이 코드는 Mateusz의 코드와 어떻게 다른가요? 단 하나가 set()을 사용하고 외관상으로 빠르다는 것을 제외하고는? –

-3

이 시도 :

# get ids of elements in second list 
l2_ids = [x.id for x in l2] 
# get elements from first list that have ids in second 
l3 = [x for x in l1 if x.id in l2_ids] 
+0

-1 목록이 매우 작지 않을 경우 목록의 구성원 자격을 테스트하는 이유는 무엇입니까? – Marcin

+0

이것은 케빈이 질문에 올린 목록을 교차시키는 빠른 방법입니다. 그것은 작동하기 때문에 나는 왜 당신이 -1을 밀 었는지 모른다. 하지만 오케이, 당신 의견입니다. –

+1

'in' 테스트가 느리다.이 알고리즘은 O (n_l1 * n_l2)이다. Python이 Marcin과 같은 빠르고 간단한 솔루션을 제공 할 때 느린 알고리즘을 사용하는 것을 권장하지 않습니다. – EOL

-1

귀하의 방법은 좀 작은 목록에 대한 상대적으로 효율적일 수있다.

세트를 사용하면 ID를 추출하고 ID의 교차 부분을 계산 한 다음 새 목록에 항목을 수집해야합니다. 다음과 같이하십시오 :

set1 = set(x.id for x in l1) 
set2 = set(x.id for x in l2) 
intersection_ids = set1 & set2 
intersection_list = [item for item in l2 if item.id in intersection_ids] 

더 짧은 목록을 스캔하거나 개체를 사전에 저장하여 좀 더 효율적으로 만들 수 있습니다. 여기

+0

요소 조회의 경우 집합 *이 빠르기 때문에 투표가 취소됩니다.그러나 필자의 대답과 같이'l2'리스트를'set (...)'과'for item in for' 두 번씩 두 번 갈 필요가 없다. – EOL

+1

Downtvoter : 자신을 설명하십시오. – Marcin