2016-03-03 4 views
5

У меня проблема с рандомизацией списка с ограничениями в Python (3). Я видел несколько других вопросов, связанных с этим, но никто из них, похоже, не решил мою проблему. Я новичок, поэтому любая помощь очень ценится!Перетасовка списка с ограничениями в Python

Я разрабатываю эксперимент, используя два типа стимулов: формы и цвета (по четыре). Мне нужно, чтобы генерировать перестановки всех 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»).

Есть ли способ сделать такое ограничение?
Заранее благодарим!

+3

До сих пор так хорошо? 'random.shuffle (x)' возвращает None, потому что он перетасовывает 'x' на место. Поэтому 'result' будет None. – zondo

+0

Это похоже на проблему с графом. Каждый узел имеет ребро, указывающее на все остальные узлы, за исключением тех, которые имеют одинаковую форму или цвет (так что (n-1)^2 ребра на узел). И тогда вам нужен случайный обход, который попадает в каждую вершину ровно один раз - гамильтоновский путь, я думаю. –

+0

@zondo О, хорошо, спасибо, что указали это. Я исправил пример. – Frederik

ответ

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 
+0

Спасибо за downvote ;-) если у вас есть лучшее решение, вы можете сообщить, что знаете –

+1

Мне тоже интересно, как и downvote. Я попробовал ваше решение и, похоже, работает. –

+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 не станет Истинными и отбросить все неверные результаты random.shuffle()

-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) 
-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] 
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)]. Тогда нет возможности для продолжения алгоритма без нарушения ограничений. Прямо сейчас, я обрабатываю его с помощью рекурсивного вызова, что не является идеальным.