这是又一年的时间,编程人员想要洗一个清单这样的,没有素驻留在其原来的位置(至少在荷兰,我们庆祝 圣尼古拉斯 和挑吸管决定谁谁写的一首诗).任何人都不会有一个很好的蟒蛇 单声明 是什么?

因此,输入,例如: 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,我的意思是 单声明.因为它出现,蟒蛇也能够压缩多个声明在一个单一的线。我不知道。目前有非常好的解决方案只使用分号,以模仿多行的行为在一个单一的线。因此:"你能做一个声明吗?"

有帮助吗?

解决方案

我发现洗牌可以被滥用成解决该

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]th人写一首诗(买礼物了!)对[i+1]th人名单:这样一来,永远不会有一个人谁画他或她自己。当然,最后一个应指向第一...

转移的每一个元素的清单由一个圆形的方式, 作为建议通过巴特, 是容易的:

>>> 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, 工作周围的事实, shuffle 返回 None...):

>>> 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]}

的代码在红宝石,但没有任何怀疑它的容易翻译到蟒

干杯

P.S .:将溶液修改阵列。

固定 O(n) 时间内的“一行”:

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的索引;一旦选择,元素将不会再次移动。

打乱后,没有元素可以驻留在其原始位置,因为:

  • 如果元素 j 被某个槽 i>j 选择,它将保留在那里
  • 否则,元素 j 将与槽 i<j 中的其他元素交换,该元素将保留在那里
  • 槽 0 中的元素除外,如果槽 1 中的元素尚未被移位,则该元素将无条件地与槽 1 中的元素(在循环的最后一次迭代中)交换。

[编辑:我认为这在逻辑上等同于 Ruby 的答案]

这一个是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

下面是输出分布时L =范围(5),用于100000个样品

((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

更新:保罗表明,上述程序是不正确的。谢谢,保罗。这里有一个不同的,更好的版本相同的程序:

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)

(OK,我有一个第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]是有效的元素下面的i的阵列v

下面是Stephan202的作为一衬垫与随机选择的移增量实现循环移位:

from random import randrange; s = range(10); r = randrange(1,len(s)-1); print s[-r:] + s[:-r]
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top