Shuffling a list with restrictions in Python

I have a problem with randomizing a list with restrictions in Python (3). I saw several other questions related to this, but none of them seemed to solve my problem. I am new, so any help is much appreciated!

I design an experiment using two types of stimuli: shapes and colors (four in each). I need to generate permutations of all 16 combinations that I performed using the 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) 

So far so good. However, I want the figure (letter) or color (number) to appear twice in a row in my result (for example, “a2”, followed by “a4” or “c2”, followed by “a2”).

Is there any way to make such a restriction?
Thanks in advance!

+5
source share
5 answers

Something like this should give a reasonable answer in a reasonable amount of time.

 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 
+1
source

One way to handle this may be to have two lists: one of the forms and one of the colors. Shuffle each list individually. Now mix the two lists. Since each list was created at random, the mixed list is also random, but you do not have two entries together.

Note that with zip, you will actually get sets of pairs that will allow you to process your test, getting each pair from the result.

In this particular case, each color is a member of the list forms, while each color is a member of the list colors

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

This gives us every random case, and does not immediately generate all 16 possibilities, and then shuffles them. This can help you better generate your test.

If you want two sets of lists to not have the same color or shape in the same position as the previous group of four, you can check this after shuffling with the previous setting.

 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 

This will result in shuffling until testresult becomes True and removes all invalid results from random.shuffle ()

+4
source

I doubt this is the best way, but this is the way to do it. If you think of your input as a type matrix

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

Then you will begin to choose a random index at each iteration so that the new index is not in the same row or in the same column of the matrix as the previous index, and such that the new element was not previously selected. By entering this into the code naively, it becomes

 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 

Outputs after pair start

 ['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'] 

Renouncement

Since this is an absolutely naive approach, it sometimes gets stuck! Suppose the last two remaining indices are [(2, 2), (3, 2)]. Then there is no way to continue the algorithm without violating the restrictions. Right now I am processing it with a recursive call, which is not ideal.

+1
source

While you can technically use itertools.permutations (I tried this first), it will take too much time.

Use this to generate random sequences without elements that have a property that follows each other:

 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
source

You can build a piece of the list by comparing a random option with the last value.

 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
source

Source: https://habr.com/ru/post/1244392/


All Articles