2012-01-12 3 views
3

이렇게 목록의 파이썬 목록은 다음과 같습니다. [1,89,1221,1919,1920,10210,...] 숫자가 몇 천 개가 넘는 나는 나는 그 안에 variabele을 가지고있다.파이썬의 숫자 집합에서 숫자의 존재를 확인하는 가장 좋은 방법은 무엇입니까

는 나는이 방법을 수행

if i in mylist: 

그러나 가장 빠른 방법이다?

일부 추가 사양 :

  • 목록이 목록은 해당 목록이 사실에 설정 될 수
  • 성능을 향상 경우 주문하실 수 있습니다 정수를
  • 목록을 보유하고
  • 에는 중복을 보유하지 (따라서 중복이 없음)
  • 목록은 어떤 종류의 컬렉션이 될 수 있습니다.
+0

세트/세트 번호의 크기가 고정되어 있습니까? – helpermethod

+0

아니요, 다를 수 있습니다. 고정 번호 목록에 대한 통찰력도 환영합니다. – Peter

+1

집합으로 변환하는 것은 비교적 비용이 많이 드는 작업이지만 'i in mylist'도 비용이 많이 듭니다. 같은 목록에서 몇 번 이상이 작업을한다면, 집합을 사용하는 것이 더 낫다. –

답변

2

집합으로 변환하고 in을 수행하는 것이 가장 빠릅니다.

if i in set(mylist): 

집합은 기본적으로 해시 테이블이며 조회는 O (1)입니다.

+0

감사합니다. 아무도 이것이 금식 방식이라고 주장하지 않으면 나중에 받아 들여야합니다 – Peter

+2

아니요. 목록을 'if' 문에서만 집합으로 변환하면 목록을 탐색하여 새로운 데이터 구조를 만들어야하기 때문에 실제로는 원래 코드보다 느립니다. – thesamet

+3

이 메서드는 반복적으로 작업을 수행하는 경우에만 더 빠릅니다. 그렇지 않으면 목록을 집합으로 변환하는 오버 헤드가 O (N) 대신 O (1)에서 검색을 수행하여 얻은 성능보다 커집니다. –

1

목록에서 세트를 만들고 세트를 교차 시키며 교차의 크기를 확인 하시겠습니까?

+0

+1 : 나는 너의 생각을 좋아한다. '?' 그것은 받아 들여진 응답을위한 후보자로하지 않습니다. (또한 : 나는 금식 방식이라고 상상할 수 없다) – Peter

+0

초기 질문을 잘못 읽었다. 숫자의 집합이 아니라 하나의 숫자가 존재하는지 확인하기를 원한다. 그럴 경우'(i in mylist)', O (n)에서 컬렉션을 생성하는 경우 직접 세트를 생성합니다.이 경우 'in'은 O (1)가됩니다 –

4

set으로의 변환은이 목록에서 여러 번 조회 할 때만 가치가 있습니다. 성능이 중요한 경우 처음부터 set으로 작업하는 경우 (요소를 삽입하는 동안) 목록을 작성하는 것보다 더 나은 성능을 제공하는지 측정해야합니다. 요컨대, 몇 가지 시도하고 측정하십시오.

그러나 단일 멤버십 테스트 용 세트로 변환하면 새 데이터 구조를 만드는 오버 헤드로 인해 비효율적입니다.

import random 
import timeit 

mylist = list(random.randint(1, 50000) for i in xrange(1000)) 
myset = set(mylist) 

s = "1919 in mylist" 
t = timeit.Timer(s, "from __main__ import mylist") 
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000) 

s = "1919 in set(mylist)" 
t = timeit.Timer(s, "from __main__ import mylist") 
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000) 

다음은 결과입니다 :

1919 in mylist:22.81 usec/pass 
1919 in set(mylist):65.42 usec/pass 
3

한 가지 방법은 다양한 방법을 테스트 timeit module을 사용하는 것입니다. 예를 들어, 다음 코드 채찍질 :

import array 
import bisect 
import random 
import timeit 

mylist = list(random.randint(1, 50000) for i in xrange(1000)) 
myset = set(mylist) 
myarray = array.array('l', mylist) 

s = "1919 in mylist" 
t = timeit.Timer(s, "from __main__ import mylist") 
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000) 

s = "1919 in myset" 
t = timeit.Timer(s, "from __main__ import myset") 
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000) 

s = "1919 in myarray" 
t = timeit.Timer(s, "from __main__ import myarray") 
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000) 

mysortedlist = sorted(mylist) 
mysortedarray = array.array('l', mysortedlist) 

s = "1919 in mysortedlist" 
t = timeit.Timer(s, "from __main__ import mysortedlist") 
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000) 

s = "1919 in mysortedarray" 
t = timeit.Timer(s, "from __main__ import mysortedarray") 
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000) 

def bisect_in(a, x): 
    i = bisect.bisect_left(a, x) 
    return (i != len(a) and a[i] == x) 

s = "bisect_in(mysortedlist, 1919)" 
t = timeit.Timer(s, "from __main__ import bisect_in, mysortedlist") 
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000) 

을 나는 다음과 같은 결과를 얻었다 :이 테스트가 가정에서 세트를 사용하는 것이 가장 빠른 것으로 다른 사람의 주장을 (지원

1919 in mylist:73.89 usec/pass 
1919 in myset:0.29 usec/pass 
1919 in myarray:103.77 usec/pass 
1919 in mysortedlist:75.12 usec/pass 
1919 in mysortedarray:114.21 usec/pass 
bisect_in(mysortedlist, 1919):4.17 usec/pass 

코드가 만든다).

+0

감사합니다 srgerg, 내 자신의 벤치 마크에서 사용하겠습니다. – Peter

1

일부 메모리 효율성을 희생하려는 경우 목록 색인이 확인하려는 값인 조회 테이블을 작성할 수 있습니다.

원본 목록 :

In [106]: %timeit i in myList 
    10000 loops, best of 3: 21.3 us per loop 

는 조회 테이블을 건물 :

In [90]: lookup = [False for i in range(max(myList)+1)] 

    In [91]: for i in myList: 
       lookup[i] = True 

    In [92]: %timeit lookup[i] 
    10000000 loops, best of 3: 50.7 ns per loop 

룩업 테이블은 여기에 정렬되지 않은 목록 이상 ~ 400 배 빠르다.

이 옵션은 목록의 최대 값이 허용 가능하게 낮고 조회 테이블을 설정할 시간이 변수가 테이블에 있는지 확인하는 데 소요되는 시간보다 현저히 짧은 경우에만 실제로 가능합니다.

흥미롭게도 Numpy 배열을 사용할 때 룩업 테이블 방법이 25 % 더 느립니다. (하지만 조회 테이블을 작성하는 것이 훨씬 빠릅니다.)

편집 :이 방법은 "i set (myList)"에서 속도면에서 2를 능가합니다.

+1

목록 정렬만으로 개선 될 수 있습니까? 정렬되지 않은 목록과 정렬되지 않은 목록에서 존재하지 않는 요소를 검색하려고 시도했지만 각각에 대해 대략 동일한 시간이 걸렸습니다. 남아있는 값을 검색 할 때 원래 목록에서 값이 있던 위치에 따라 정렬 된 목록에서 시간이 다소 걸렸습니다. – srgerg

+0

정확합니다. 이것은 실수입니다. 정렬은 프로세스 속도를 높이는 속도로 프로세스를 느려지 게 만듭니다. 더 많은 이유가 세트 또는 조회 테이블을 사용합니다. 나는 오도하지 않도록 글을 바 꾸었습니다. – ebarr

관련 문제