문제

그것은 일년의 시간을 다시하는 프로그래머 원하는 셔플 목록은 없는 요소에있는 원래의 위치(적어도에서 네덜란드,우리는 우리를 축하 부상 선택 빨대한 결정을 쓰는 시).사람이 좋은 Python 단일 문의 는?

그래서,입력 예: range(10)

출력를 들어: [2,8,4,1,3,7,5,9,6,0]

잘못된 것 출력 [2,8,4,1,3,5,7,9,6,0]5 은 원래 위치입니다.이 의미는 사람 5 시를 신고 적은 재미 있습니다.

편집 많은 사람들이 반복 할당으로하는 데 필요한 운이 좋 을 찾는 사실 솔루션에는 만족입니다.이것은 나쁜 방법으로서 이론은 이 무한한다.더 나은 방법은 실로 제안하여,그러나 나는 그것을 얻을 수 없습으로 oneliner 이유 중 하나 또는 다른...

편집 여 oneliner,말 단일 문의.으로 나타나고,파이썬은 또한 압축 할 수있는 여러 문 on a single line.지 않았다는 것을 알고.현재는 아주 좋은 솔루션을 사용하여 세미콜론을 모방하는 여러 행동에 하나의 라인입니다.따라서:"당신은 그것을 할 수 있습니에서 하나의 문입니까?"

도움이 되었습니까?

해결책

나는 셔플이 이것을 해결하기 위해 남용 될 수 있음을 발견했다

from random import shuffle
L = ["Anne", "Beth", "Cath", "Dave", "Emma"]
shuffle(L, int=lambda n: int(n - 1))
print L

분포는 균일하지 않지만 이는 요구 사항이 아닙니다.

#For 100,000 samples

(('Beth', 'Cath', 'Dave', 'Emma', 'Anne'), 13417)
(('Beth', 'Cath', 'Emma', 'Anne', 'Dave'), 6572)
(('Beth', 'Dave', 'Anne', 'Emma', 'Cath'), 3417)
(('Beth', 'Dave', 'Emma', 'Cath', 'Anne'), 6581)
(('Beth', 'Emma', 'Anne', 'Cath', 'Dave'), 3364)
(('Beth', 'Emma', 'Dave', 'Anne', 'Cath'), 6635)
(('Cath', 'Anne', 'Dave', 'Emma', 'Beth'), 1703)
(('Cath', 'Anne', 'Emma', 'Beth', 'Dave'), 1705)
(('Cath', 'Dave', 'Beth', 'Emma', 'Anne'), 6583)
(('Cath', 'Dave', 'Emma', 'Anne', 'Beth'), 3286)
(('Cath', 'Emma', 'Beth', 'Anne', 'Dave'), 3325)
(('Cath', 'Emma', 'Dave', 'Beth', 'Anne'), 3421)
(('Dave', 'Anne', 'Beth', 'Emma', 'Cath'), 1653)
(('Dave', 'Anne', 'Emma', 'Cath', 'Beth'), 1664)
(('Dave', 'Cath', 'Anne', 'Emma', 'Beth'), 3349)
(('Dave', 'Cath', 'Emma', 'Beth', 'Anne'), 6727)
(('Dave', 'Emma', 'Anne', 'Beth', 'Cath'), 3319)
(('Dave', 'Emma', 'Beth', 'Cath', 'Anne'), 3323)
(('Emma', 'Anne', 'Beth', 'Cath', 'Dave'), 1682)
(('Emma', 'Anne', 'Dave', 'Beth', 'Cath'), 1656)
(('Emma', 'Cath', 'Anne', 'Beth', 'Dave'), 3276)
(('Emma', 'Cath', 'Dave', 'Anne', 'Beth'), 6638)
(('Emma', 'Dave', 'Anne', 'Cath', 'Beth'), 3358)
(('Emma', 'Dave', 'Beth', 'Anne', 'Cath'), 3346)

균일 한 분포의 경우이 (더 긴) 버전을 사용할 수 있습니다.

from random import shuffle,randint
L=["Anne", "Beth", "Cath", "Dave", "Emma"]
shuffle(L, random=lambda: 1, int=lambda n: randint(0, n - 2))
print L

# For 100,000 samples

(('Beth', 'Cath', 'Dave', 'Emma', 'Anne'), 4157)
(('Beth', 'Cath', 'Emma', 'Anne', 'Dave'), 4155)
(('Beth', 'Dave', 'Anne', 'Emma', 'Cath'), 4099)
(('Beth', 'Dave', 'Emma', 'Cath', 'Anne'), 4141)
(('Beth', 'Emma', 'Anne', 'Cath', 'Dave'), 4243)
(('Beth', 'Emma', 'Dave', 'Anne', 'Cath'), 4208)
(('Cath', 'Anne', 'Dave', 'Emma', 'Beth'), 4219)
(('Cath', 'Anne', 'Emma', 'Beth', 'Dave'), 4087)
(('Cath', 'Dave', 'Beth', 'Emma', 'Anne'), 4117)
(('Cath', 'Dave', 'Emma', 'Anne', 'Beth'), 4127)
(('Cath', 'Emma', 'Beth', 'Anne', 'Dave'), 4198)
(('Cath', 'Emma', 'Dave', 'Beth', 'Anne'), 4210)
(('Dave', 'Anne', 'Beth', 'Emma', 'Cath'), 4179)
(('Dave', 'Anne', 'Emma', 'Cath', 'Beth'), 4119)
(('Dave', 'Cath', 'Anne', 'Emma', 'Beth'), 4143)
(('Dave', 'Cath', 'Emma', 'Beth', 'Anne'), 4203)
(('Dave', 'Emma', 'Anne', 'Beth', 'Cath'), 4252)
(('Dave', 'Emma', 'Beth', 'Cath', 'Anne'), 4159)
(('Emma', 'Anne', 'Beth', 'Cath', 'Dave'), 4193)
(('Emma', 'Anne', 'Dave', 'Beth', 'Cath'), 4177)
(('Emma', 'Cath', 'Anne', 'Beth', 'Dave'), 4087)
(('Emma', 'Cath', 'Dave', 'Anne', 'Beth'), 4150)
(('Emma', 'Dave', 'Anne', 'Cath', 'Beth'), 4268)
(('Emma', 'Dave', 'Beth', 'Anne', 'Cath'), 4109)

작동 방식

다음은 코드입니다 random.shuffle()

def shuffle(self, x, random=None, int=int):
    """x, random=random.random -> shuffle list x in place; return None.

    Optional arg random is a 0-argument function returning a random
    float in [0.0, 1.0); by default, the standard random.random.
    """

    if random is None:
        random = self.random
    for i in reversed(xrange(1, len(x))):
        # pick an element in x[:i+1] with which to exchange x[i]
        j = int(random() * (i+1))
        x[i], x[j] = x[j], x[i]

두 솔루션 모두 라인을 타겟팅하여 작동합니다 j = int(random() * (i+1))

첫 번째 (균일하지 않은)는 효과적으로 라인을 이와 같이 작동시킵니다.

j = int(random() * (i + 1) - 1)

따라서 (1..i) 범위 대신 (0..i-1)을 얻습니다.

두 번째 솔루션이 대체됩니다 random() 항상 1을 반환하고 사용하는 함수로 randint 대신에 int. 그래서 선은 이제 이와 같이 작동합니다

j = randint(0, i - 1)

다른 팁

숫자 목록을 섞은 후에 [i]그 사람은시를 쓰고 (그리고 선물을 사십시오!) [i+1]목록에있는 사람 : 그런 식으로, 자신을 이끌어내는 사람은 없습니다. 물론 마지막 것은 첫 번째를 가리 려야합니다 ...

이동의 모든 요소가 목록으로 중 하나에 원형으로, 에 의해 제안 Bart, 은 쉽습니다:

>>> def shift(seq):
...     return seq[-1:] + seq[:-1]
... 
>>> shift(range(10))
[9, 0, 1, 2, 3, 4, 5, 6, 7, 8]

으로 무작위 솔루션:이 경우에 요청에 대한 하나-라이너입니다 좋은 생각이 아닌,이후 명백한 기능을 사용하여,즉 random.shuffle,해당 작업을 수행한다.다른 말로:그 부작용, 뭔가 하나는 일반적으로 피하려고 목록에 함축.가 이 주위에 방법이지만,로 인,즉 사용하여 random.sample.다음 코드는 두 개의 중 하나-라이너는 이러한 기능을 사용(의 사용을 참고 not shuffle, 일,주위 사실 shuffleNone...):

>>> from itertools import repeat
>>> from random import shuffle
>>> def shake_it(seq):
...     return next(c for c in repeat(seq[::]) if not shuffle(c) and all(a != b for a, b in zip(seq, c)))
... 
>>> shake_it(range(10))
[7, 9, 0, 2, 6, 8, 5, 1, 4, 3]
>>> 
>>> from itertools import count
>>> from random import sample
>>> def shake_it(seq):
...     return next(c for c in (sample(seq, len(seq)) for _ in count()) if all(a != b for a, b in zip(seq, c)))
... 
>>> shake_it(range(10))
[1, 3, 9, 5, 2, 6, 8, 4, 0, 7]

내 자신,내가 가서 이 하나:

>>> def shake_it(seq):
...     res = seq[::]
...     while any(a == b for a, b in zip(res, seq)):
...         shuffle(res)
...     return res
... 
>>> shake_it(range(10))
[5, 7, 9, 2, 6, 8, 3, 0, 4, 1]

다음은 O (N) 시간 및 O (1) 추가 메모리로 수행하는 방법입니다.

이해할 수있는 코드 :

def shuffle(a)
  n = a.length
  (0..n - 2).each do |i|
    r = rand(n - i - 1) + i + 1
    a[r], a[i] = a[i], a[r]
  end
  a
end

하나의 라이너 ( "A"가 배열이라고 가정합니다) :

n = a.length and (0..n - 2).each {|i| r = rand(n - i - 1) + i + 1; a[r], a[i] = a[i], a[r]}

코드는 루비에 있지만 의심 할 여지없이 파이썬에 쉽게 번역 할 수 있습니다.

건배

추신 : 솔루션은 배열을 수정합니다.

고정 된 O (n) 시간의 "1- 라이너":

import random; a=range(10)  # setup (could read in names instead)
for i in range(len(a)-1,0,-1): j=random.randint(0,i-1); a[j],a[i]=a[i],a[j]
print a  # output

루프는 최대 인덱스 (Len (a) -1)에서 다음 작은 (1)까지 요소를 선택합니다. 요소 K에 대한 선택 풀에는 0에서 K-1의 지수 만 포함됩니다. 일단 선택되면 요소가 다시 움직이지 않습니다.

스크램블 후에는 요소가 원래 위치에 상주 할 수 없습니다.

  • 일부 슬롯 i> j에 요소 j가 선택되면 거기에 머무를 것입니다.
  • 그렇지 않으면 요소 j는 슬롯 i의 다른 요소로 교체됩니다.
  • 슬롯 0의 요소를 제외하고, 이는 아직 변위되지 않은 경우 슬롯 1 (루프의 최종 반복에서)의 요소로 무조건 교체됩니다.

편집 : 이것은 루비 답변과 논리적으로 동일합니다.

이것은 O (n)입니다. 루프에서 가져 오는 것은 약간 어리석지 만 하나의 라이너를 원했습니다.

L=range(10)
for i in range(1,len(L)):import random;r=random.randint(0,i-1);L[i],L[r]=L[r],L[i]
print L

100000 샘플의 L = 범위 (5)의 출력 분포는 다음과 같습니다.

((1, 2, 3, 4, 0), 4231)
((1, 2, 4, 0, 3), 4115)
((1, 3, 0, 4, 2), 4151)
((1, 3, 4, 2, 0), 4108)
((1, 4, 0, 2, 3), 4254)
((1, 4, 3, 0, 2), 4101)
((2, 0, 3, 4, 1), 4158)
((2, 0, 4, 1, 3), 4177)
((2, 3, 1, 4, 0), 4190)
((2, 3, 4, 0, 1), 4117)
((2, 4, 1, 0, 3), 4194)
((2, 4, 3, 1, 0), 4205)
((3, 0, 1, 4, 2), 4325)
((3, 0, 4, 2, 1), 4109)
((3, 2, 0, 4, 1), 4131)
((3, 2, 4, 1, 0), 4153)
((3, 4, 0, 1, 2), 4081)
((3, 4, 1, 2, 0), 4118)
((4, 0, 1, 2, 3), 4294)
((4, 0, 3, 1, 2), 4167)
((4, 2, 0, 1, 3), 4220)
((4, 2, 3, 0, 1), 4179)
((4, 3, 0, 2, 1), 4090)
((4, 3, 1, 0, 2), 4132)

오랫동안 나의 첫 번째 Python 프로그램. 위의 많은 프로그램과 달리 이것은 O (n) 시간이 걸립니다.

s = set(range(10))
r = list()
for i in range(10):
    s2 = s - set([i])
    val = s2.pop()
    r.append(val)
    s.discard(val)

print r

업데이트: Paul은 위의 프로그램이 틀렸다는 것을 보여주었습니다. 고마워요, 폴. 다음은 동일한 프로그램의 다른 버전입니다.

s = range(10)
for i in range(9):
    r = random.randrange(i+1, 10)
    s[i], s[r] = s[r], s[i]

print s

죄송합니다 이것은 하나의 라이너가 아니지만 이것은 작동합니다

import random
def sinterklaas(n):
    l=[]
    for a in range(n):
        l.append(-1)

    i = 0
    while i < 10:
        index = random.randint(0,n-1)
        if l[index] == -1 and index != i:
        l[index] = i
            i += 1

건배

import random; u = range(10)
while sum(u[i]==i for i in range(10)): random.shuffle(u)

(좋아요, 저도 거기에 줄 0이 있습니다 ...)

O (n)의 경우 :

u=range(10); random.shuffle(u); v=[ u[u[i]] for i in range(10) ]; return [ v[(u[i]+1)%10] for i in u ]

u 기능의 역수입니다 v, 그래서 v[u[i]+1] 효과적으로 배열에서 다음 요소입니다 v.

다음은 Stephan202의 원형 교대가 무작위로 선택된 시프트 증분을 갖는 1 라이너로 구현되었습니다.

from random import randrange; s = range(10); r = randrange(1,len(s)-1); print s[-r:] + s[:-r]
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top