Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中对带有限制的列表进行无序排列_Python_Shuffle_Restrictions - Fatal编程技术网

在Python中对带有限制的列表进行无序排列

在Python中对带有限制的列表进行无序排列,python,shuffle,restrictions,Python,Shuffle,Restrictions,在Python(3)中,我在随机化带有限制的列表时遇到了一个问题。我已经看到了一些与此相关的其他问题,但没有一个真正解决了我的问题。我是初学者,非常感谢您的帮助 我正在设计一个实验,使用两种类型的刺激:形状和颜色(每种四种)。我需要生成所有16种组合的排列,这是我用random.shuffle-function完成的: import random # letters are shapes, numbers are colors x=["a1","a2","a3","a4","b1","b2",

在Python(3)中,我在随机化带有限制的列表时遇到了一个问题。我已经看到了一些与此相关的其他问题,但没有一个真正解决了我的问题。我是初学者,非常感谢您的帮助

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

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”)

有没有办法做出这样的限制?

提前谢谢

处理这个问题的一种方法可能是有两个列表,一个是形状列表,另一个是颜色列表。逐个洗牌每个列表。现在将这两个列表混合在一起。由于每个列表都是随机生成的,所以混合列表也是随机的,但您没有任何两个条目同时存在

请注意,使用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()中的所有无效结果,而您可以在技术上使用
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)

通过将随机选项与最后一个值进行比较,可以逐段构建列表

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]

我怀疑这是最好的方法,但这是一种方法。如果你把你的输入想象成这样一个矩阵

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
两次运行后的输出 免责声明
由于这是一个完全幼稚的方法,它有时会卡住!假设剩下的最后两个指数是[(2,2),(3,2)]。那么,在不打破限制的情况下,算法是不可能继续进行的。现在,我用递归调用来处理它,这并不理想。

类似的东西应该在合理的时间内给出合理的答案

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

到目前为止还好吗
random.shuffle(x)
返回None,因为它将
x
就地洗牌。因此,
result
将为None。这似乎是一个图形问题。每个节点都有一条指向所有其他节点的边,但形状或颜色相同的节点除外(因此每个节点有(n-1)^2条边)。然后你需要一个随机的遍历,它精确地击中每个顶点一次——我认为是哈密顿路径。@zondo哦,对了,谢谢你指出了这一点。我已经纠正了这个例子。谢谢你的否决票;-)如果你有更好的解决方案,你可以自由地告诉你,我对否决票也很好奇。我尝试了你的解决方案,似乎很有效。非常感谢,Daniele!这正是我想要的。
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