[python] 목록에서 임의의 요소를 팝하는 가장 비단뱀적인 방법은 무엇입니까?

x나중에 목록에 요소가 포함되지 않도록 한 요소를 임의로 팝하려는 알 수없는 길이 의 목록이 있다고 가정 해 보겠습니다. 이것을 수행하는 가장 비단뱀적인 방법은 무엇입니까?

나는의 다소 손재주가 combincation를 사용하여 작업을 수행 할 수 있습니다 pop, random.randint그리고 len, 짧은 또는 더 좋은 솔루션을보고 싶습니다 :

import random
x = [1,2,3,4,5,6]
x.pop(random.randint(0,len(x)-1))

내가 달성하려는 것은 목록에서 무작위 요소를 연속적으로 팝하는 것입니다. (즉, 한 요소를 무작위로 팝하고 사전으로 이동하고, 다른 요소를 무작위로 팝하고 다른 사전으로 이동합니다. …)

Python 2.6을 사용하고 있으며 검색 기능을 통해 솔루션을 찾지 못했습니다.



답변

당신이하고있는 것처럼 보이는 것은 처음에는 그다지 Pythonic으로 보이지 않습니다. 목록은 내가 아는 모든 파이썬 구현에서 배열로 구현되므로 목록 중간에서 항목을 제거해서는 안됩니다 O(n). 따라서 이것은 작업입니다.

알고리즘의 일부로이 기능이 정말로 필요한 경우 blist중간에서 효율적인 삭제를 지원 하는 데이터 구조를 확인해야 합니다.

순수 Python에서 나머지 요소에 액세스 할 필요가없는 경우 수행 할 수있는 작업은 목록을 먼저 섞은 다음 반복하는 것입니다.

lst = [1,2,3]
random.shuffle(lst)
for x in lst:
  # ...

당신이 경우 정말 필요한 , (코드 냄새, IMHO의 비트가있는) 나머지를 최소 할 수 있습니다 pop()지금 목록의 끝에서 (빨리!)

while lst:
  x = lst.pop()
  # do something with the element      

일반적으로 상태를 변경하는 대신에보다 기능적인 스타일을 사용하면 (목록 에서처럼) 프로그램을 더 우아하게 표현할 수 있습니다.


답변

그보다 훨씬 나아지지는 않을 것이지만 여기에 약간의 개선이 있습니다.

x.pop(random.randrange(len(x)))

에 대한 문서 random.randrange():

random.randrange ([start], stop [, step])
에서 임의로 선택된 요소를 반환합니다 range(start, stop, step). 이는와 동일 choice(range(start, stop, step))하지만 실제로 범위 객체를 빌드하지는 않습니다.


답변

나머지 목록 요소의 순서가 중요하지 않은 경우 목록에서 임의의 인덱스에 있는 단일 요소 를 제거하려면 :

import random

L = [1,2,3,4,5,6]
i = random.randrange(len(L)) # get random index
L[i], L[-1] = L[-1], L[i]    # swap with the last element
x = L.pop()                  # pop last element O(1)

스왑은 목록 중간에서 삭제시 O (n) 동작을 방지하는 데 사용됩니다.


답변

또 다른 대안이 있습니다. 먼저 목록을 섞은 다음 더 이상 요소가 남아 있지 않을 때까지 목록의 요소를 터뜨리는 것이 어떻습니까? 이렇게 :

import random

x = [1,2,3,4,5,6]
random.shuffle(x)

while x:
    p = x.pop()
    # do your stuff with p


답변

이를 수행하는 한 가지 방법은 다음과 같습니다.

x.remove(random.choice(x))


답변

목록에서 나오지 않는 동안 중복없이 목록에서 X 개의 임의 항목을 가져 오려고 시도하는 동안 Google에서이 질문이 발생했습니다. 내가 결국 사용한 것은 다음과 같습니다.

items = [1, 2, 3, 4, 5]
items_needed = 2
from random import shuffle
shuffle(items)
for item in items[:items_needed]:
    print(item)

전체 목록을 셔플하지만 일부만 사용하므로 약간 비효율적 일 수 있지만 최적화 전문가가 아니므로 틀릴 수 있습니다.


답변

나는 이것이 오래된 질문이라는 것을 알고 있지만 문서화를 위해서 :

당신 (같은 질문을 검색하는 사람)이 당신이하고있는 일을하고 있다면, 목록에서 무작위로 k 개의 항목을 선택하는 것입니다 (여기서 k <= len (yourlist)), 그러나 각 항목이 더 이상 선택되지 않도록 확인 한 번 이상 (= 대체없이 샘플링) @ jf-sebastian이 제안한 것처럼 random.sample을 사용할 수 있습니다 . 그러나 유스 케이스에 대해 더 많이 알지 못하면 이것이 필요한지 모르겠습니다.