PythonUserNew
PythonUserNew

Reputation: 91

Python random list

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?

Upvotes: 7

Views: 319

Answers (5)

Raymond Hettinger
Raymond Hettinger

Reputation: 226754

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)

Upvotes: 0

orlp
orlp

Reputation: 118006

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.

Upvotes: 1

macabeus
macabeus

Reputation: 4592

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)

Upvotes: 1

Maciek
Maciek

Reputation: 3234

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)

Upvotes: 2

John Coleman
John Coleman

Reputation: 52008

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]

Upvotes: 3

Related Questions