파이썬 세트와리스트


187

파이썬에서 어떤 데이터 구조가 더 효율적 / 빠른가? 그 순서가 나에게 중요하지 않다고 가정하고 어쨌든 중복을 확인하려고한다면 파이썬이 파이썬 목록보다 느리게 설정됩니까?

답변:


231

그것은 당신이 그것을하려는 의도에 달려 있습니다.

세트에 객체가 있는지 여부를 판별 할 때 세트가 상당히 빠르지 x in s만 컨텐츠를 반복 할 때 목록보다 속도가 느립니다.

timeit 모듈 을 사용 하여 상황에 맞는 것이 더 빠른지 확인할 수 있습니다.


4
요점 : "세트가 훨씬 빠릅니다", 기본 구현이 더 빨라집니다.
overexchange

스크립팅 언어는 기본 구현을 숨기는 것을 좋아하지만이 명백한 단순성이 항상 좋은 것은 아니며 소프트웨어를 설계 할 때 '데이터 구조'에 대한 인식이 필요합니다.
Christophe Roussy

4
반복하는 동안 목록이 목록보다 크게 느리지 않습니다.
omerfarukdogan

39
세트와리스트는 모두 선형 시간 반복을가집니다. 하나는 다른 것보다 "느리다"고 말하는 것은 잘못된 생각이며이 답을 읽는 새로운 프로그래머들을 혼란스럽게합니다.
habnabit

@habnabit 둘 다 선형 시간 반복이 있다고 말합니다. 이것이 동일한 반복 시간을 의미합니까? 그렇다면 차이점은 무엇입니까?
Mohammed Noureldin

153

값을 반복하려는 경우 목록이 세트보다 약간 빠릅니다.

그러나 항목이 포함되어 있는지 확인하려는 경우 세트가 목록보다 훨씬 빠릅니다. 그러나 고유 한 항목 만 포함 할 수 있습니다.

튜플은 불변성을 제외하고 목록과 거의 동일한 방식으로 수행됩니다.

반복

>>> def iter_test(iterable):
...     for i in iterable:
...         pass
...
>>> from timeit import timeit
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = set(range(10000))",
...     number=100000)
12.666952133178711
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = list(range(10000))",
...     number=100000)
9.917098999023438
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = tuple(range(10000))",
...     number=100000)
9.865639209747314

물체가 있는지 확인

>>> def in_test(iterable):
...     for i in range(1000):
...         if i in iterable:
...             pass
...
>>> from timeit import timeit
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = set(range(1000))",
...     number=10000)
0.5591847896575928
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = list(range(1000))",
...     number=10000)
50.18339991569519
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = tuple(range(1000))",
...     number=10000)
51.597304821014404

6
(초기화 세트-> 5.5300979614257812) (초기화 목록-> 1.8846848011016846) (초기화 튜플-> 1.8730108737945557) 12GB RAM이있는 인텔 코어 i5 쿼드 코어의 크기가 10,000 인 항목을 발견했습니다. 이것도 고려해야합니다.
ThePracticalOne

4
객체 생성을 제거하기 위해 코드를 업데이트했습니다. timeit 루프의 설정 단계는 한 번만 호출됩니다 ( docs.python.org/2/library/timeit.html#timeit.Timer.timeit ).
Ellis Percival

7

목록 성능 :

>>> import timeit
>>> timeit.timeit(stmt='10**6 in a', setup='a = range(10**6)', number=100000)
0.008128150348026608

성능 설정 :

>>> timeit.timeit(stmt='10**6 in a', setup='a = set(range(10**6))', number=100000)
0.005674857488571661

Tuple 은 목록과 비슷하지만 수정할 수 없으므로 Tuple 을 고려할 수 있습니다. 메모리를 약간 덜 차지하고 액세스 속도가 더 빠릅니다. 융통성이 없지만 목록보다 효율적입니다. 일반적인 용도는 사전 키 역할을하는 것입니다.

세트는 또한 시퀀스 구조이지만 목록과 튜플과는 두 가지 차이점이 있습니다. 세트에는 순서가 있지만 순서는 임의적이며 프로그래머가 제어하지 않습니다. 두 번째 차이점은 세트의 요소가 고유해야한다는 것입니다.

set정의에 의해. [ 파이썬 | 위키 ].

>>> x = set([1, 1, 2, 2, 3, 3])
>>> x
{1, 2, 3}

4
먼저 , 더 이상 사용되지 않는 라이브러리가 아닌 set내장 유형 링크 ( docs.python.org/2/library/stdtypes.html#set )로 업데이트해야합니다 sets. 둘째, "세트는 시퀀스 구조이기도합니다."기본 제공 유형 링크에서 다음을 읽으십시오. "정렬되지 않은 콜렉션이므로 세트는 요소 위치 또는 삽입 순서를 기록하지 않습니다. 따라서 세트는 인덱싱, 슬라이싱 또는 기타를 지원하지 않습니다. 순서와 유사한 행동 "
Seaux

7
range아닙니다 list. range커스텀 __contains__매직 메소드 가있는 특수 클래스입니다 .
Ryne Wang

@RyneWang 이것은 사실이지만 Python3에만 해당됩니다. Python2에서 범위는 보통의 목록을 반환합니다 (그런 끔찍한 일을 존재 이유의 xrange)
노엘 Vilela

7

Set거의 즉각적인 '포함'점검으로 인해 승리 : https://en.wikipedia.org/wiki/Hash_table

목록 구현 : 일반적으로 금속에 가까운 낮은 수준의 배열로, 반복 및 요소 인덱스 별 임의 액세스에 적합합니다.

구현 설정 : https://en.wikipedia.org/wiki/Hash_table , 목록에서 반복하지 않지만 키에서 해시 를 계산하여 요소를 찾으 므로 키 요소의 특성과 해시에 따라 다릅니다. 함수. dict에 사용되는 것과 유사합니다. 내가 의심 list당신은 매우 몇 가지 요소 (<5)이있는 경우 더 빨리 될 수있다, 더 큰 요소는 더 카운트 setA가 수표를 포함하기위한 수행합니다. 또한 요소 추가 및 제거가 빠릅니다. 또한 세트를 만드는 데 비용이 든다는 사실을 항상 명심하십시오!

참고 : list가 이미 정렬되어 있으면 검색 list이 매우 빠를 수 있지만 일반적인 경우 set에는 포함 검사가 더 빠르고 간단합니다.


8
금속에 가깝습니까? 파이썬의 맥락에서 그것은 무엇을 의미합니까? 목록이 세트보다 금속에 얼마나 가깝습니까?
roganjosh

@roganjosh, python은 여전히 ​​컴퓨터에서 실행되며 'array'와 같은 list와 같은 일부 구현은 하드웨어가 잘하는 것에 더 가깝습니다. 하지만 stackoverflow.com/questions/176011/… 추상화뿐만 아니라 구현에 대해 조금 아는 것이 좋습니다.
Christophe Roussy

2

tl; dr

그들은 기본적 의미 데이터에 대한 작업을 수행하는 데 사용되기 때문에 데이터 구조 (DS)가 중요하다 : 약간의 입력을 받아 , 그것을 처리출력을 돌려주고 .

일부 데이터 구조는 특정 경우에 다른 데이터 구조보다 유용합니다. 따라서 어떤 (DS)가 더 효율적 / 빠른지 묻는 것은 불공평합니다. 나이프와 포크 사이에서 어떤 도구가 더 효율적인지 묻는 것과 같습니다. 나는 모든 상황에 달려 있습니다.

기울기

목록은 변경 가능한 순서 이며 일반적으로 동종 항목의 컬렉션을 저장하는 데 사용됩니다 .

세트

집합 객체는 고유 한 해시 가능 객체정렬되지 않은 모음입니다 . 일반적으로 멤버십을 테스트하고 시퀀스에서 중복을 제거하고 교점, 합집합, 차이 및 대칭 차이와 같은 수학 연산을 계산하는 데 사용됩니다.

용법

일부 답변에서 값을 반복 할 때 목록이 세트보다 훨씬 빠릅니다. 반면에 항목이 포함되어 있는지 확인할 때 목록보다 세트가 더 빠릅니다. 따라서 말할 수있는 유일한 것은 목록이 특정 작업에 대한 집합보다 낫다는 것입니다.


2

값이 소수의 리터럴 중 하나인지 CPython을 사용하여 확인할 때 결과에 ​​관심이있었습니다. set대 파이썬 3으로 승리 tuple, list그리고 or:

from timeit import timeit

def in_test1():
  for i in range(1000):
    if i in (314, 628):
      pass

def in_test2():
  for i in range(1000):
    if i in [314, 628]:
      pass

def in_test3():
  for i in range(1000):
    if i in {314, 628}:
      pass

def in_test4():
  for i in range(1000):
    if i == 314 or i == 628:
      pass

print("tuple")
print(timeit("in_test1()", setup="from __main__ import in_test1", number=100000))
print("list")
print(timeit("in_test2()", setup="from __main__ import in_test2", number=100000))
print("set")
print(timeit("in_test3()", setup="from __main__ import in_test3", number=100000))
print("or")
print(timeit("in_test4()", setup="from __main__ import in_test4", number=100000))

산출:

tuple
4.735646052286029
list
4.7308746771886945
set
3.5755991376936436
or
4.687681658193469

3 ~ 5 리터럴의 경우 set여전히 넓은 마진으로 이기고 or가장 느립니다.

파이썬 2에서는 set항상 느립니다. or2 ~ 3 리터 가장 빠른, 그리고 tuple하고 list있습니다 빠른 4 개 이상 리터럴. tuple대 속도를 구분할 수 없었습니다 list.

테스트 할 값이 루프 내에서 리터럴을 생성하는 대신 함수 외부의 전역 변수에 캐시되면 setPython 2에서도 매번 승리했습니다.

이 결과는 Core i7의 64 비트 CPython에 적용됩니다.


0

유스 케이스가 존재를 참조하거나 검색하는 데 제한이있는 Set 구현과 유스 케이스가 반복을 수행 해야하는 Tuple 구현을 권장합니다. 목록은 저수준 구현이며 상당한 메모리 오버 헤드가 필요합니다.


1
실제로, 세트 사용시기와 사용시기 사이의 적절한 구별은 실제로 가장 중요합니다. 하위 수준 API를 스크립팅하지 않으면 관련된 메모리 오버 헤드, 풋 프린트에 대해 걱정하지 않아도됩니다.

0
from datetime import datetime
listA = range(10000000)
setA = set(listA)
tupA = tuple(listA)
#Source Code

def calc(data, type):
start = datetime.now()
if data in type:
print ""
end = datetime.now()
print end-start

calc(9999, listA)
calc(9999, tupA)
calc(9999, setA)

3 개 모두에 대해 10 회 반복을 비교 한 결과 : 비교


0

세트는 더 빠르며, Morover는 세트가 더 많은 기능을 얻습니다.

set1 = {"Harry Potter", "James Bond", "Iron Man"}
set2 = {"Captain America", "Black Widow", "Hulk", "Harry Potter", "James Bond"}

우리는 쉽게 두 세트에 합류 할 수 있습니다 :

set3 = set1.union(set2)

두 가지 공통점이 무엇인지 알아보십시오.

set3 = set1.intersection(set2)

둘 다의 차이점을 찾으십시오.

set3 = set1.difference(set2)

그리고 훨씬 더! 그냥 사용해보십시오, 그들은 재미 있습니다! 또한 2 목록 내의 다른 값이나 2 목록 내의 공통 값에 대해 작업 해야하는 경우 목록을 세트로 변환하는 것을 선호하며 많은 프로그래머가 그렇게합니다. 그것이 도움이되기를 바랍니다 :-)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.