我想生成列表的n个随机版本,以使每次随机化的顺序都不同于之前的顺序,而且每个元素的位置都必须不同于之前列表中的位置。我已经生成了该列表的所有可能排列的列表,但是我在如何选择符合我的条件的子列表上遇到了麻烦。我在想也许列表理解可以工作,但不确定如何完成。
# constraints: n <= 12
lst = ['John', 'William', 'Michael', 'Victor', 'Tom', 'Charley', 'Patrick', 'David']
permutations = list(itertools.permutations(lst))
randomized_lists = [i for i in permutations if <conditions>]
有什么想法可以做到吗?另外,是否有更好(更有效)的方法来解决该问题?
答案 0 :(得分:1)
这可以通过修改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)]
答案 1 :(得分:0)
您可以使用此列表理解:
result = [i for i in permutations if any(a != b for a, b in zip(i, lst))]
我们正在any(a == b for a, b in zip(i, lst)
测试lst
中同一索引上是否有任何匹配项以及该行中的排列。
答案 2 :(得分:0)
只有第二个条件是必要的:如果所有元素均不在其原始位置,则顺序将有所不同。您无需查看所有可能的排列并随机选择一个排列(这比混洗直到满足您的条件效率低得多),而是可以生成符合规格的列表。
您的列表有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)可以轻松修改为如果必要/可能,则更统一。