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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.