在Python中使用限制重新排列列表

时间:2016-03-03 21:37:27

标签: python shuffle restrictions

我在使用Python(3)中的限制随机化列表时遇到问题。我已经看到了一些与此相关的其他问题,但它们似乎都没有解决我的问题。我是初学者,所以非常感谢任何帮助!

我正在设计一个使用两种刺激类型的实验:形状和颜色(每种刺激四种)。我需要生成所有16种组合的排列,我用random.shuffle函数完成了:

import random

# letters are shapes, numbers are colors
x=["a1","a2","a3","a4","b1","b2","b3","b4","c1","c2","c3","c4","d1","d2","d3","d4"]

random.shuffle(x)

到目前为止一切顺利。但是,我想避免在我的结果中连续出现两次形状(字母)或颜色(数字)(例如“a2”后跟“a4”,或“c2”后跟“a2”)。

有没有办法做出这样的限制?
提前谢谢!

5 个答案:

答案 0 :(得分:4)

处理这种情况的一种方法可能是让两个列表中的一个是形状,一个是颜色。单独随机播放每个列表。现在混合两个列表。由于每个列表都是随机构建的,因此混合列表也是随机的,但您没有任何两个条目。

请注意,使用zip,您实际上会获得一组对,这使您可以通过从结果中获取每对来处理您的测试。

在这种特殊情况下,每种颜色都是列表形状的成员,而每种颜色都是列表颜色的成员

shapes = ['a', 'b', 'c', 'd']
colors = ['1', '2', '3', '4']
zip(shapes, colors)
[('a', '1'), ('b', '2'), ('c', '3'), ('d', '4')]

这给了我们每个人的洗牌,而不是一次产生所有16种可能性,然后将它们混洗。这可以让您更好地生成测试。

如果您想确保两组列表在与前一组四个相同的位置中没有相同的颜色或形状,那么您可以在对前一个设置进行随机播放后对其进行测试。

testing = True
while testing:
    newcolors = colors
    random.shuffle(newcolors)
    # perform the test that you want to make get testresult True or False
    if testresult:
        colors = newcolors
        testing = False

这将继续改组,直到testresult变为True并丢弃来自random.shuffle()的所有无效结果

答案 1 :(得分:1)

我怀疑这是最好的方式,但这是一种做法。如果您将输入视为像这样的矩阵

a1, b1, c1, d1
a2, b2, c2, d2
a3, b3, c3, d3
a4, b4, c4, d4

然后你的目标是在每次迭代时选择一个随机索引,这样新的索引不会与前一个索引在同一行或矩阵的同一列中,并且之前没有选择新元素。把它放到代码天真地,它变成

import random
shapes_and_colors=["a1","a2","a3","a4","b1","b2","b3","b4","c1","c2","c3","c4","d1","d2","d3","d4"]
nRows = 4
nCols = 4
inds = [(x,y) for x in range(nRows) for y in range(nCols)]
def make_random(someArr):
    toRet = []
    n = len(someArr)
    for i in range(n):
        possible = [thing for thing in someArr if thing not in toRet]
        prev = poss = None
        while poss is None:
            next_val = random.choice(possible)
            if next_val == prev:
                #failed so try again
                return make_random(someArr)
            if not toRet or (next_val[0] != toRet[-1][0] and next_val[1] != toRet[-1][1]):
                poss = next_val 
            prev = next_val
        toRet += poss,
    return toRet



ans= [thing for thing in make_random(shapes_and_colors)]
print ans

情侣跑完后的输出

['c3', 'd4', 'c1', 'd3', 'b1', 'a4', 'b3', 'c4', 'a3', 'b2', 'a1', 'c2', 'd1', 'a2', 'b4', 'd2']
['d4', 'b3', 'c1', 'a4', 'b2', 'c4', 'd3', 'a1', 'c3', 'a2', 'b4', 'd2', 'a3', 'b1', 'c2', 'd1']

声明

由于这是一种非常天真的方法,它有时会卡住!因此,假设剩下的最后两个指数是[(2,2),(3,2)]。然后,在没有违反限制的情况下,算法无法继续进行。现在,我正在使用递归调用来处理它,这并不理想。

答案 2 :(得分:1)

这样的事情应该在合理的时间内给出合理的答案

import random
while 1:
    choices = ["a1", "a2","a3","b1","b2","b3","c1","c2","c3"]

    shuffle = []

    last = ""

    while choices:
        l = choices
        if last:
            l = [x for x in l if x[0] != last[0] and x[1] != last[1]]
        if not l:
            #no valid solution
            break 
        newEl = random.choice(l)
        last = newEl
        shuffle.append(newEl)
        choices.remove(newEl)
    if not choices:
        print(shuffle)
        break

答案 3 :(得分:-1)

虽然你可以在技术上使用itertools.permutations(我先尝试过),但这需要太长时间。

使用此选项生成随机序列,而不包含彼此共享属性的项目:

from random import shuffle

x=["a1","a2","a3","a4","b1","b2","b3","b4","c1","c2","c3","c4","d1","d2","d3","d4"]

def pairwise(some_list):
    one = iter(some_list)
    two = iter(some_list)
    next(two)
    for first, second in zip(one, two):
        yield first, second

while True:
    shuffle(x)
    for first, second in pairwise(x):
        if first[0] == second[0] or first[1] == second[1]:
            break
    else: # nobreak:
        print(x)

答案 4 :(得分:-1)

您可以通过将随机选项与最后一个值进行比较来明确构建列表。

import random

options = ["a1", "a2", "a3", "a4", "b1", "b2", "b3", "b4",
           "c1", "c2", "c3", "c4", "d1", "d2", "d3", "d4"]

j = random.choice(range(len(options)))
result = [options.pop(j)]
last = result[-1]
while options:
    j = random.choice(range(len(options)))
    candidate = options[j]
    if all([x != y for x, y in zip(last, candidate)]):
        result.append(options.pop(j))
        last = result[-1]