创建一个 M*N 矩阵,由 1-90 的唯一数字组成

Creating an M*N matrix of unique numbers from 1-90

我想在 python 中开发一种算法,该算法 returns 使用某些 rules/conditions 随机填充 1 到 90 的数字的 18x9 矩阵。

规则

#1 - Maintain an array of 18x9 between 1 and 90. 
#2 - First column contains 1-10, second column contains 11-20, etc.
#3 - Each row must have 5 numbers. Other columns should be set to 0.
#4 - Numbers must be arranged in ascending order from top to bottom in a column

到目前为止我做了什么?

import numpy as np

columns = 9
rows = 18
n_per_row = 5

matrix = np.zeros((rows, columns), dtype=int)

# Keep track of available places at each row.
available_places = {k: n_per_row for k in range(rows)}

# Shuffle order in which we fill the columns.
col_order = np.arange(columns)
np.random.shuffle(col_order)

for column in col_order:
    # Indices of available rows.
    indices = [c for c in available_places if available_places[c]]
    
    # Sample which row to use of the available.
    indices = np.random.choice(indices, size=min(len(indices), 10), replace=False)
    # print(indices)
    
    # Values for this column.
    col_values = np.random.choice(list(np.arange(1, 10+1)), size=min(len(indices), 10), replace=False) + column*10
    
    # Fill in ascending order.
    matrix[sorted(indices), column] = sorted(col_values)

    for idx in indices:
        available_places[idx] -= 1
print(matrix)

    

结果

 [[ 0  0  0 31  0 51  0 71 81]
 [ 1 11  0  0  0 52 61 72  0]
 [ 0  0 21 32 41  0 62 73  0]
 [ 0  0 22 33  0  0  0 74 82]
 [ 0 12 23  0 42  0 63  0 83]
 [ 2 13 24 34  0 53  0  0  0]
 [ 3  0  0  0 43 54 64  0 84]
 [ 4  0  0  0 44 55 65  0 85]
 [ 5 14  0  0 45  0 66  0 86]
 [ 6  0 25 35 46  0  0 75  0]
 [ 7 15 26 36  0  0  0  0 87]
 [ 8 16  0  0 47  0  0 76 88]
 [ 0 17 27  0 48  0  0 77 89]
 [ 0 18  0  0 49 56 67 78  0]
 [ 9  0 28 39  0 57  0 79  0]
 [ 0  0 29  0 50 58 68 80  0]
 [ 0 19 30 40  0 59 69  0  0]
 [10 20  0  0  0 60 70  0 90]]

预期结果:https://images.meesho.com/images/products/56485141/snksv_512.jpg

4条规则的最终结果
每行 5 个值
每列 10 个值,以 1、11、21 等开始,按升序排列
(请注意,如图所示,这些规则不适用于宾果游戏)

============ final matrix ===============
--------------------------------
[1, 11, 21, 31, 41, 0, 0, 0, 0]
[2, 12, 0, 32, 42, 0, 61, 0, 0]
[0, 13, 0, 33, 0, 0, 62, 71, 81]
[3, 0, 0, 34, 0, 0, 63, 72, 82]
[0, 0, 22, 0, 0, 51, 64, 73, 83]
[4, 14, 23, 35, 0, 52, 0, 0, 0]
[5, 0, 24, 0, 43, 53, 0, 0, 84]
[6, 15, 0, 36, 44, 54, 0, 0, 0]
[7, 0, 0, 37, 0, 0, 65, 74, 85]
[0, 0, 0, 0, 45, 55, 66, 75, 86]
[8, 16, 25, 0, 0, 0, 67, 76, 0]
[0, 0, 26, 0, 46, 56, 0, 77, 87]
[9, 17, 0, 0, 0, 0, 68, 78, 88]
[10, 18, 0, 0, 0, 57, 0, 79, 89]
[0, 19, 27, 38, 47, 0, 0, 80, 0]
[0, 20, 28, 39, 48, 58, 0, 0, 0]
[0, 0, 29, 0, 49, 59, 69, 0, 90]
[0, 0, 30, 40, 50, 60, 70, 0, 0]
--------------------------------   

原则:
首先建立一个矩阵,其中 0 和 1 设置为未来值的占位符。
随机化矩阵中每个单元格的 0 或 1,但调查一行中的 1 个和列中的 1 个以遵守约束。
由于 random 可能会提前给出足够的 1,因此在第一次尝试时无法满足这两个约束。 Prog 自动重试并跟踪每次尝试以进行观察。 (在我的测试中看到的最大值:10 个循环,平均:<=3 个循环)
一旦获得令人满意的 0 & 1 矩阵,将每个 1 替换为每个列的相应值。
解决方案:

import random
# #1 - Maintain an array of 18x9 (between 1 and 90)
maxRow = 18
maxCol = 9


# #2 - First column contains 1-10, second column contains 11-20, etc.
# ie first column 1 start from 1 and have 10 entries, column 2 start from 11 and have 10 entries, etc. 
origins = [i*10 +1 for i in range(maxCol)]  #[1, 11, 21, 31, 41, 51, 61, 71, 81]
maxInCol = [10 for i in range(maxCol)]      #[10, 10, 10, 10, 10, 10, 10, 10, 10]

# comfort  : display matrix
def showMatrix():
    print('--------------------------------')
    for row in range(len(matrix)):
        print(matrix[row])
    print('--------------------------------')

# comfort : count #values in a col 
def countInCol(col):
    count = 0
    for row in range(maxRow):
        count+=matrix[row][col]
    return count     

# verify the rules of 5 per row and 10 per cols 
def verify():
    ok = True
    showMatrix()
    # count elements in a col
    for col in range(maxCol):
        count = 0
        for row in range(maxRow):
            count+= matrix[row][col]
        if(count!= maxInCol[col]): 
            print ('*** wrong # of elements in col {0} : {1} instead of {2}'.format(col, count,maxInCol[col]))
            ok = False
    # count elements in a row 
    for row in range(maxRow):
        count = 0
        for col in range(maxCol):
            count+= matrix[row][col]
        if(count!=5): 
            print('***** wrong # of elements in row {0} : {1}'.format(row, count))
            ok = False
    if (not ok): print( '********************************************')
    return ok 

# -- main ----
# need to iterate in case of no more value to complete a col 
tour = 1
maxTour = 100 #security limit 
while True:
    # prepare a matrix of rows of cols of 0 
    matrix = [[0 for i in range(maxCol)] for i in range(18)]
    # begin to fill some places with 1 instead of 0 
    for row in range(maxRow):
        count = 0
        for col in range(maxCol):
            if (count==5): break   # line is already full with 5 elt
            # random a 0 or 1 
            placeHolder = random.choice([0,1])
            #  if the remaining cols of this row needs to be 1 to complete at 5/row
            if (5-count) == (maxCol-col): 
                placeHolder = 1 # must complete the row 
            else: 
                inCol = countInCol(col)
                # 10 places max in col 
                if (inCol)==maxInCol[col]: placeHolder = 0 # this col is full
                # constraint : if the remaining rows of this col need to be 1 to complete the expected 10 values
                if(maxRow-row) == (maxInCol[col]-inCol): placeHolder = 1
            matrix[row][col] = placeHolder
            count+= placeHolder
    #-------- some case are not correct . prog loops 

    if verify(): 
        print(' ok after {0} loop(s)'.format(tour))
        break
    # security infinite loop 
    if (tour>=maxTour): break
    tour +=1

# now replace the placeholders by successive values per col 
print('\n============ final matrix ===============')
for row in range(maxRow):
    for col in range(maxCol):
        if  matrix[row][col]==1:
            matrix[row][col] = origins[col]
            origins[col]+=1

showMatrix()

HTH