는 방법을 검색하는 요소 세트에서 제거하지 않고 그것은?

StackOverflow https://stackoverflow.com/questions/59825

  •  09-06-2019
  •  | 
  •  

문제

가 다음과 같다:

>>> s = set([1, 2, 3])

어떻게 받을 수 있 value(값)의 s 하지 않고 s.pop()?내가 떠나고 싶어하는 항목에서 설정될 때까지 내가 그것을 제거할 수 있는 뭔가가 될 수 있의 확인 후에 비동기 호출,다른 호스트.

빠르고 더러운:

>>> elem = s.pop()
>>> s.add(elem)

하지만 당신이 알고있는 더 좋은 방법?이상적으로 일정한 시간입니다.

도움이 되었습니까?

해결책

두 가지 옵션이 필요하지 않은 복사하는 전체 세트:

for e in s:
    break
# e is now an element from s

나...

e = next(iter(s))

그러나 일반적으로,설정을 지원하지 않는 인덱싱이나 슬라이스.

다른 팁

적어도 코드:

>>> s = set([1, 2, 3])
>>> list(s)[0]
1

분명 이들 새로운 목록에 포함하는 각 멤버의 설정,그렇지 않으면 설정이 매우 큰 것입니다.

를 제공합 타이밍 그림 뒤에 서로 다른 접근,다음과 같은 코드를 살펴봅니다.Get()은 내 사용자 지정한 파이썬의 setobject.c 되 pop()을 제거하지 않고 요소입니다.

from timeit import *

stats = ["for i in xrange(1000): iter(s).next()   ",
         "for i in xrange(1000): \n\tfor x in s: \n\t\tbreak",
         "for i in xrange(1000): s.add(s.pop())   ",
         "for i in xrange(1000): s.get()          "]

for stat in stats:
    t = Timer(stat, setup="s=set(range(100))")
    try:
        print "Time for %s:\t %f"%(stat, t.timeit(number=1000))
    except:
        t.print_exc()

출력 결과는 다음과 같습니다.

$ ./test_get.py
Time for for i in xrange(1000): iter(s).next()   :       0.433080
Time for for i in xrange(1000):
        for x in s:
                break:   0.148695
Time for for i in xrange(1000): s.add(s.pop())   :       0.317418
Time for for i in xrange(1000): s.get()          :       0.146673

에 대한/break 해결책이 가장 빠르다(때로는 보다 빠른 주문을 얻을()솔루션).

tl;박사

for first_item in muh_set: break 남아 최적의 접근 방식에서는 Python3.x. 저주를,Guido.

이렇게

환 또 다른 설정의 Python3.x 타이밍,에서 추정 wr.의 우수한 Python2.x-특정 응답.달리 AChampion's 동등하게 도움이 Python3.x-특정 응답, 타이밍이 아래 시간 이상값 솔루션을 제안된 상 포함하여:

코드 조각을 위해 큰 기쁨

턴에,조정에,시간은:

from timeit import Timer

stats = [
    "for i in range(1000): \n\tfor x in s: \n\t\tbreak",
    "for i in range(1000): next(iter(s))",
    "for i in range(1000): s.add(s.pop())",
    "for i in range(1000): list(s)[0]",
    "for i in range(1000): random.sample(s, 1)",
]

for stat in stats:
    t = Timer(stat, setup="import random\ns=set(range(100))")
    try:
        print("Time for %s:\t %f"%(stat, t.timeit(number=1000)))
    except:
        t.print_exc()

빠르게 사용한 타이밍

보라! 주문하는 가장 빠른 느린 조각:

$ ./test_get.py
Time for for i in range(1000): 
    for x in s: 
        break:   0.249871
Time for for i in range(1000): next(iter(s)):    0.526266
Time for for i in range(1000): s.add(s.pop()):   0.658832
Time for for i in range(1000): list(s)[0]:   4.117106
Time for for i in range(1000): random.sample(s, 1):  21.851104

니다.온 가족을위한

당연히, 수동 반복에 남아 있는 두 배 이상 빠르 으로 다음이 가장 빠른 솔루션입니다.지만 간격은 감소에서 나쁜 오래된 Python2.×일(에서는 수동 반복 최소 네 배로 빠른),그것은 실망하 PEP20 날에 열광하는 가장 자세한 솔루션이 최고입니다.에서 이상으로 변환한 설정으로 목록을 추출하는 첫 번째 요소의 세트로 예상된다. 감사 Guido 수 있습니다,그의 빛이 계속드립니다.

놀랍게도, RNG 기반 솔루션이 절대적으로 끔찍하다. 목록에 변환,나쁘지 random 는 끔찍한 소스 케이크입니다.그래서 많 임의의 숫자는 하나님.

제조직들은 격려 set.get_first() 방법은 우리를 위해 이미 이다.당신이 이것을 읽는 경우,그들은:"시기 바랍니다.무언가를 하십시오."

때문에 당신이 원하는 임의의 요소,이 또한 작동합니다:

>>> import random
>>> s = set([1,2,3])
>>> random.sample(s, 1)
[2]

문서를 보이지 않는 언급하의 성능 random.sample.에서 정말 빠른 실험적인 테스트와 함께 거대한 목록과는 거대한 설정,그것을 일정 시간에 대한 목록은 아니지만 설정합니다.또한 반복을 설정하지 않는 임의의;이 순서가 정의되지 않지만 예측:

>>> list(set(range(10))) == range(10)
True 

만약 임의성은 중요하고 필요를 요소의 무리에서 일정 시간(큰 세트),난 사용 random.sample 변환하는 첫 번째 목록:

>>> lst = list(s) # once, O(len(s))?
...
>>> e = random.sample(lst, 1)[0] # constant time

궁금하는 방법 기능을 수행에 대한 다른 세트,그래서 내가 기준:

from random import sample

def ForLoop(s):
    for e in s:
        break
    return e

def IterNext(s):
    return next(iter(s))

def ListIndex(s):
    return list(s)[0]

def PopAdd(s):
    e = s.pop()
    s.add(e)
    return e

def RandomSample(s):
    return sample(s, 1)

def SetUnpacking(s):
    e, *_ = s
    return e

from simple_benchmark import benchmark

b = benchmark([ForLoop, IterNext, ListIndex, PopAdd, RandomSample, SetUnpacking],
              {2**i: set(range(2**i)) for i in range(1, 20)},
              argument_name='set size',
              function_aliases={first: 'First'})

b.plot()

enter image description here

이 그림을 명확하게 표시되는 어떤 방법(RandomSample, SetUnpackingListIndex)의 크기에 따라 달라집합을 설정하고 피해야에서는 일반적인 경우(적어도 한 경우의 성능 할 중요합니다).이미 표시된 다른 답변을 가장 빠른 방법입니다 ForLoop.

그러나 한의는 일정한 시간에 방법이 사용되는 성과 차이를 무시할 수있을 것입니다.


iteration_utilities (면책 조항:나는 저자)포함되어 편리한 기능이 사용하기 위해 경우: first:

>>> from iteration_utilities import first
>>> first({1,2,3,4})
1

나 또한 그것을 포함하는지에서 위에 있는 벤치마크.그것은 경쟁 할 수 있습으로 다른 두"빠른"솔루션이지만 차이가 없거나 방법입니다.

내가 사용 유틸리티 기능을 썼다.그것의 이름은 오해의 소지가 다소기 때문에 그것의 종류를 의미할 수 있 임의 항목입니다.

def anyitem(iterable):
    try:
        return iter(iterable).next()
    except StopIteration:
        return None

겉보기에 가장 컴팩트 (6 문자)도 매우 느리 을 얻을 수있는 방법 설정하는 요소(에 의해 가능 PEP3132):

e,*_=s

Python3.5 이상 사용할 수도 있습니다 이것은 7-기호는 식을(감사 PEP448):

[*s][0]

모두 옵션은 대략 1000 배 더 느린 내 컴퓨터에서 보다를 반복 방법입니다.

다음@wr.게시물에,나는 이와 유사한 결과를 얻을 수(대 Python3.5)

from timeit import *

stats = ["for i in range(1000): next(iter(s))",
         "for i in range(1000): \n\tfor x in s: \n\t\tbreak",
         "for i in range(1000): s.add(s.pop())"]

for stat in stats:
    t = Timer(stat, setup="s=set(range(100000))")
    try:
        print("Time for %s:\t %f"%(stat, t.timeit(number=1000)))
    except:
        t.print_exc()

출력:

Time for for i in range(1000): next(iter(s)):    0.205888
Time for for i in range(1000): 
    for x in s: 
        break:                                   0.083397
Time for for i in range(1000): s.add(s.pop()):   0.226570

그러나 변경하는 경우 기본 설정(예를 들어,전화 remove())가 나쁘게 반복 가능한 예(for, iter):

from timeit import *

stats = ["while s:\n\ta = next(iter(s))\n\ts.remove(a)",
         "while s:\n\tfor x in s: break\n\ts.remove(x)",
         "while s:\n\tx=s.pop()\n\ts.add(x)\n\ts.remove(x)"]

for stat in stats:
    t = Timer(stat, setup="s=set(range(100000))")
    try:
        print("Time for %s:\t %f"%(stat, t.timeit(number=1000)))
    except:
        t.print_exc()

결과:

Time for while s:
    a = next(iter(s))
    s.remove(a):             2.938494
Time for while s:
    for x in s: break
    s.remove(x):             2.728367
Time for while s:
    x=s.pop()
    s.add(x)
    s.remove(x):             0.030272

는 방법에 대 s.copy().pop()?난 그것을 초과하지만,그것은 작동한다고 그것은 간단합니다.그것은 최고의 작품은 세트는 그러나,그것이 복사본을 전체를 설정합니다.

또 다른 옵션은 사전을 사용하는 값으로 당신은 걱정하지 않는다.E.g.,


poor_man_set = {}
poor_man_set[1] = None
poor_man_set[2] = None
poor_man_set[3] = None
...

치료할 수 있습으로 키 설정을 제외하고는 그들은 단지 배열:


keys = poor_man_set.keys()
print "Some key = %s" % keys[0]

이 선택은 당신의 코드가 호환로,사전set versions of Python.그것은 어쩌면 최고 대답을 하지만 그것은 또 다른 옵션입니다.

편집:도 수행할 수 있습 같은 것이 이 사실을 숨기는 것을 사용한 영어 대신에 배열이나 설정:


poor_man_set = {}
poor_man_set[1] = None
poor_man_set[2] = None
poor_man_set[3] = None
poor_man_set = poor_man_set.keys()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top