7

I'm new to Python, and have some problems with creating random lists.

I'm using random.sample(range(x, x), y).

I want to get 4 lists with unique numbers, from 1-4, so I have been using this

a = random.sample(range(1, 5), 4) b = random.sample(range(1, 5), 4) c = random.sample(range(1, 5), 4) d = random.sample(range(1, 5), 4) 

So I get for example

a = 1, 3, 2, 4 b = 1, 4, 3, 2 c = 2, 3, 1, 4 d = 4, 2, 3, 1 

How can I make it that the column are also unique?

3
  • yes, but only the numbers 1- 4 :) Commented Nov 27, 2015 at 15:53
  • Are you trying to generate a random Latin square? Commented Nov 27, 2015 at 16:01
  • @ John Coleman, yes, i need to generate a latin square Commented Nov 27, 2015 at 16:20

5 Answers 5

3

Absent a clear mathematical theory, I distrust anything other than a somewhat hit-and-miss approach. In particular, backtracking approaches can introduce a subtle bias:

from random import shuffle def isLatin(square): #assumes that square is an nxn list #where each row is a permutation of 1..n n = len(square[0]) return all(len(set(col)) == n for col in zip(*square)) def randSquare(n): row = [i for i in range(1,1+n)] square = [] for i in range(n): shuffle(row) square.append(row[:]) return square def randLatin(n): #uses a hit and miss approach while True: square = randSquare(n) if isLatin(square): return square 

Typical output:

>>> s = randLatin(4) >>> for r in s: print(r) [4, 1, 3, 2] [2, 3, 4, 1] [1, 4, 2, 3] [3, 2, 1, 4] 
Sign up to request clarification or add additional context in comments.

2 Comments

thank you so much guys, i'm gonna experiment and try it out :D
This method is completely without bias, but this is a very inefficient method however as N grows. For the last row there are N! permutations, but only 1 is feasible. This puts the runtime at least at O(N!). Depending on the number of bits that the Python random number generator has internally it might never terminate for big N.
2

Totally random then:

def gen_matrix(): first_row = random.sample(range(1, 5), 4) tmp = first_row + first_row rows = [] for i in range(4): rows.append(tmp[i:i+4]) return random.sample(rows, 4) 

2 Comments

Probably the best answer for this. Short concise and works. And here I was doing overly complex functions to do this. Nice +1
This is effectively identical to my answer, except coded differently.
1

Create a list of all the elements, and as will filling the line, remove the used element.

import random def fill_line(length): my_list = list(range(length)) to_return = [] for i in range(length): x = random.choice(my_list) to_return.append(x) my_list.remove(x) return to_return x = [fill_line(4) for i in range(4)] print(x) 

Comments

1

Probably the simplest way is to create a valid matrix, and then shuffle the rows, and then shuffle the columns:

import random def random_square(U): U = list(U) rows = [U[i:] + U[:i] for i in range(len(U))] random.shuffle(rows) rows_t = [list(i) for i in zip(*rows)] random.shuffle(rows_t) return rows_t 

Usage:

>>> random_square(range(1, 1+4)) [[2, 3, 4, 1], [4, 1, 2, 3], [3, 4, 1, 2], [1, 2, 3, 4]] 

This should be able to create any valid matrix with equal probability. After doing some reading it seems that this still has bias, although I don't fully comprehend why yet.

Comments

0

I would build a random latin square by 1) start with a single random permutation, 2) populate the rows with rotations 3) shuffle the rows 4) transpose the square 5) shuffle the rows again:

from collections import deque from random import shuffle def random_latin_square(elements): elements = list(elements) shuffle(elements) square = [] for i in range(len(elements)): square.append(list(elements)) elements = elements[1:] + [elements[0]] shuffle(square) square[:] = zip(*square) shuffle(square) return square if __name__ == '__main__': from pprint import pprint square = random_latin_square('ABCD') pprint(square) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.