这可以通过修改Fisher–Yates shuffle算法来避免与自身交换一项来完成。也就是说,对于 k 中的每个项目(其中 k 从0开始),而不是选择[0,k]
或[k,n - 1]
中的随机项目(包括k
),在[0,k)
或(k,n - 1]
中选择一个随机项目(不包括k
),然后将 k 处的项目与该随机项目交换。
以下方法实现了这个想法:
import random
def shuffle_diff_pos(list):
""" Returns a shuffled list in which
each item moves to a different position. """
list=[x for x in list]
if len(list)>=2:
i=len(list)-1
while i>0:
k=random.randint(0,i-1)
tmp=list[i];list[i]=list[k];list[k]=tmp
i-=1
return list
lst = ['John','William','Michael','Victor','Tom','Charley','Patrick','David']
randomized_lists = [shuffle_diff_pos(lst) for _ in range(12)]
,
您可以使用此列表理解:
result = [i for i in permutations if any(a != b for a,b in zip(i,lst))]
我们正在any(a == b for a,lst)
测试lst
中同一索引上是否有任何匹配项以及该行中的排列。
,
只有第二个条件是必要的:如果所有元素均不在其原始位置,则顺序将有所不同。您无需查看所有可能的排列并随机选择一个排列(这比混洗直到满足您的条件效率低得多),而是可以生成符合规格的列表。
您的列表有8个元素,这意味着每个职位可以有7个选项之一(当前所有元素除外)。这等效于将一个矩阵放置在零矩阵中,从而使每个矩阵都不会与另一个矩阵占据相同的行或列(正常改组),但存在元素不能位于主对角线上的限制,这使事情变得复杂。
您可以实施Fisher-Yates-like随机播放,其中包括限制。这将使您的列表随机化,而不必筛选大量的排列。
使用索引来避免放置冲突可能要容易得多,而不是在交换每个元素时查找它们的位置。
n = len(lst)
ind = list(range(n))
for i in range(n - 1):
# Case 1: Swap out necessary,conflictonly with self
if ind[i] == i:
swap_ind = random.randrange(i + 1,n)
else:
try:
# Case 2: swap might cause conflict
ind_of_i = ind.index(i,i + 1)
swap_ind = random.randrange(i,n - 1)
if swap_ind >= ind_of_i:
swap_ind += 1
except ValueError:
# Case 3: no conflict,full range available
swap_ind = random.randrange(i,n)
ind[i],ind[swap_ind] = ind[swap_ind],ind[i]
您现在有了一个随机排序的索引列表,这些索引中的任何一个都没有终止于它的开始位置。您可以使用以下方式排列输入列表
result = [lst[i] for i in ind]
请记住,检查ind[swap_ind]
的实现在时间上效率很低,并且实际上抵消了对索引进行排序而不是对实际值进行排序的好处。您可以用第二个列表替换它,该列表维护索引的反向查找表的位置,并将其与ind
交换。结果将是O(1)
查找和两倍的内存利用率。
我不确定结果在所有可用排列的空间上的统一程度如何,但我怀疑(a)它可能足以满足您的需求,并且(b)可以轻松修改为如果必要/可能,则更统一。
本文链接:https://www.f2er.com/3157209.html