'Generate a 2d array with fixed sum of its rows and columns (Python)

I'm trying to generate a 2d array with random positive integers with a fixed sum of each column and row.

For example:

Sum of each column: [8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8]

Sum of each row: [48, 14, 24, 52, 30]

I'm trying to solve this issue by this code:

def restore_matrix(row, column):
    rr = len(row)
    cc = len(column)
    matrix = [[0] * cc for i in range(rr)]
    for i in range(rr):
        for j in range(cc):
            rr = min(row[i], column[j])
            r = rr
            matrix[i][j] = r
            row[i] -= matrix[i][j]
            column[j] -= matrix[i][j]
    return matrix

columns = [8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8]
rows = [48, 14, 24, 52, 30]

my_answer = restore_matrix(rows, columns)
print(my_answer)
li = [sum(x) for x in my_answer]
print(li)

This code gives me one solution, can I make this code generate random integers each time I run this code?



Solution 1:[1]

Can't leave comments, but the answer by Frank Yellin wouldn't work if as the question says, it's to work for positive numbers.

Imagine the following:

 3  ,  0  ,  -  (12)
 3  ,  4  ,  -  (12)
 -  ,  -  ,  -  (12)
(12), (12), (12)

You have to put 9 in cell(0,2).

 3  ,  0  ,  9  (12) OK
 3  ,  4  ,  -  (12)
 -  ,  -  ,  -  (12)
(12), (12), (12)

But now what to put in cell(1,2)?

  • If we put cell(1,2)=5, then the second row would pass but the third column overshoots.
 3  ,  0  ,  9  (12) OK
 3  ,  4  ,  5  (12) OK
 -  ,  -  ,  -  (12)
(12), (12), (12)
            NOK
  • If we put cell(1,2)=3, then last column would pass but the second column falls short.
 3  ,  0  ,  9  (12) OK
 3  ,  4  ,  3  (12) NOK
 -  ,  -  ,  -  (12)
(12), (12), (12)
             OK

But at any rate, here's the implementation of what they said (I was also working on it at the same time and post it in case it helps):

import random


def restore_matrix(row, column):
    # making a duplicate of the passed list so as not to mutate the global lists.
    row_sums = [*row]
    col_sums = [*column]
    len_rows = len(row_sums)
    len_cols = len(col_sums)
    matrix = [[0] * len_cols for i in range(len_rows)]

    for i in range(len_rows-1):
        for j in range(len_cols-1):
            _min = min(row_sums[i], col_sums[j])
            num = random.randint(0, _min)
            matrix[i][j] = num
            row_sums[i] -= num
            col_sums[j] -= num

    # last col
    j = len_cols - 1
    for i in range(len_rows-1):
        num = row_sums[i]
        matrix[i][j] = num
        row_sums[i] -= num
        col_sums[j] -= num

    # last row
    i = len_rows - 1
    for j in range(len_cols):
        num = col_sums[j]
        matrix[i][j] = num
        row_sums[i] -= num
        col_sums[j] -= num

    return matrix



columns = [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8]
rows = [48, 14, 24, 52, 30]

my_answer = restore_matrix(rows, columns)
print(my_answer)

sum_of_rows = [sum(r) for r in my_answer]
sum_of_cols = [sum([r[c] for r in my_answer]) for c in range(len(columns))]

print(sum_of_rows == rows)
print(sum_of_cols == columns)

Again, this doesn't guarantee that last row will be positive.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1