所以,我有一个小组列表
[['a', 'b'], ['c', 'd', 'e'], ['f']]
我需要洗牌这个列表的扁平化版本
[a, b, c, d, e, f]
使同一组的元素彼此相距一定距离。 E. g。
[a, c, b, d, f, e]
而非[a, c, b, d, e, f]
,因为d
和e
属于同一群组。
我不在乎距离是否只是一个元素或更多元素,但任何元素必须不在其组的另一个元素附近。这有什么算法吗?
该算法还需要判断是否无法完成此操作。
答案 0 :(得分:5)
此代码生成原始组列表的副本,并且每次从(每个时刻)最大剩余组中获取随机元素。不完全随机化,但是当没有超过一半所有元素的组时,它应该适用于任何情况。
import random
list_of_groups = [['a', 'b'], ['c', 'd', 'e'], ['f']]
l = [group[:] for group in list_of_groups] # make a copy
random.shuffle(l)
out = []
prev_i = -1
while any(a for a in l):
new_i = max(((i,a) for i,a in enumerate(l) if i != prev_i), key=lambda x: len(x[1]))[0]
out.append(l[new_i].pop(random.randint(0, len(l[new_i]) - 1)))
prev_i = new_i
print out
答案 1 :(得分:2)
让我采取与当前答案不同的方法
基本原则是shuffle列表中的每个列表,sort它基于长度,zip_longest基于从列表传递的变量参数,最后{{3}列表然后打开它。特别要注意的是我们如何将列表作为变量args传递给迭代器,这使得生活变得更容易: - )
让我们说你的清单是
yourList=[['a', 'b'],['c', 'd', 'e'],['f']]
我的工作清单(复制后保存原始清单)
workList=yourList[::]
随机播放列表中的每个列表
[random.shuffle(x) for x in workList]
接下来,我们根据每个列表的长度对List进行排序
workList.sort(key=len,reverse=True)
然后最终链接到压缩的混洗列表
[x for x in itertools.chain(*[x for x in itertools.izip_longest(*workList)]) if x]
你的最终名单看起来像是
['e', 'b', 'f', 'c', 'a', 'd']
答案 2 :(得分:0)
只是一个快速而不是非常优雅的代码:
example = [[1, 2], [3, 4, 5], [6]]
result = []
block = None
last_block = None
while example:
if block:
last_block = block
block = choice(example)
if last_block:
example.append(last_block)
element = choice(block)
result.append(element)
block.remove(element)
example.remove(block)
example = [a for a in example if a]
print result
虽然可能发生的问题是只有一个块可供选择的情况。就像在这种情况下:
[1,6,2,3,4,5]
当然必须有某种方法来捕获这个异常,但是现在我希望这段代码可以让你知道如何解决你的问题。
答案 3 :(得分:0)
我要给出“愚蠢”,直截了当的回答:只需将列表弄平,然后反复随机移动,直到你得到一个可接受的列表。
此方法具有在所有合法列表中均匀分布的特性,并且易于证明是正确且直接的代码。唯一的缺点是它可能会变慢 - 但考虑到另一条评论中提到的用例,我相信它会足够快。
至于“是否有可能” - 乍一看,我认为当且仅当没有任何一组有超过一半的元素时,应该是可能的。如果您考虑相邻的第一个和最后一个元素,请将“向上舍入”更改为“向下舍入”。