验证列中是否已存在数字时出现问题

2024-05-16 11:36:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图验证列表中的数字是否已经存在于列矩阵中,但仍在重复。有人能帮我吗?你知道吗

import random
    numbers = [1,2,3,4,5,6,7,8,9]
    matrix = [[None for i in range(9)] for j in range(9)]

def createMatrix():
    for i in range(9):
        for j in range(9):
            cop = numbers[:]
            random.shuffle(cop)
            while matrix[i][j] is None:
                temp = veriCol(matrix, j, cop)
                if temp == 0:
                    matriz[i] = cop
                else: 
                    return None


def veriCol(matrix, col, value):
    tmp = 0
    for l in range(9):
        #print("Vc {}".format(l)),
        if value == matrix[l][col]:
            tmp = 1

    return tmp


createMatrix()
for i in range(9):
    print(matriz[i])

Tags: innoneforifdefrangerandomtemp
2条回答

除非出于其他目的需要索引,否则不要使用索引循环;使用列表理解和for .. in循环。你知道吗

def is_number_in_column(number, column, matrix):
  return any(row[column] == number for row in matrix)

如果您的任务是输入数字,以便在任何列中都没有重复的数字,请考虑记住已用完的列。你知道吗

  • 您可以在第一行中放置任意数字序列。你知道吗
  • 在第二行中,您应该取出第一列中使用的数字(让它成为X),将其余的数字洗牌,然后将X放在除第一列以外的任意位置。你知道吗
  • 在第三行,有两个数字用完了,X来自第一列,而Y来自第二列。把它们剪下来,把剩下的洗牌,然后把X放在除第一个以外的任何位置,然后把Y放在除第二个以外的任何位置。你知道吗

等;为一般情况制定这一点,它更容易您当前的算法。使用集合而不是列表有帮助。你知道吗

您可以为所使用的列值维护一个集合列表。新“洗牌”生产线的验证可以更直接地完成。对于子矩阵组也一样,尽管您需要使用间接(或复杂的索引计算)将位置映射到组集:

import random

def createMatrix():
    matrix  = []
    numbers = [1,2,3,4,5,6,7,8,9]
    groups  = [ [0,0,0, 1,1,1, 2,2,2] ] * 3
    groups += [ [3,3,3, 4,4,4, 5,5,5] ] * 3
    groups += [ [6,6,6, 7,7,7, 8,8,8] ] * 3
    while len(matrix) < 9:
        matrix    = []
        colSets   = [ set() for _ in range(9) ]
        groupSets = [ set() for _ in range(9) ]
        for row in range(9):
            for _ in range(133496): # try multiple permutations for row (36.79%)
                random.shuffle(numbers)
                if any( n in used for n,used in zip(numbers,colSets) ):
                    continue # column conflict
                if any( n in groupSets[g] for n,g in zip(numbers,groups[row]) ):
                    continue # sub-matrix group conflict
                matrix.append(numbers.copy())
                for n,used in zip(numbers,colSets):     used.add(n)
                for n,g    in zip(numbers,groups[row]): groupSets[g].add(n)
                break
            if len (matrix) == row: break # restart if failed to produce a row
    return matrix

sudoku = createMatrix()
for line in sudoku:
    print(line)

如果您试图生成一个随机的拉丁方,一种更快的技术是将工作基线随机化,而不是在试错过程中反复检查随机数集的有效性:

import random

numbers = random.sample(range(1,10),9)
cols    = random.sample(range(9),9)
rows    = random.sample(range(9),9)
matrix  = [[numbers[(r+c)%9] for c in cols] for r in rows]

for line in matrix: print(line)  

[8, 9, 1, 7, 6, 4, 5, 3, 2]
[5, 2, 9, 6, 4, 3, 1, 8, 7]
[2, 4, 6, 8, 5, 1, 7, 9, 3]
[1, 7, 2, 4, 3, 8, 9, 5, 6]
[7, 3, 4, 5, 1, 9, 6, 2, 8]
[3, 1, 5, 2, 7, 6, 8, 4, 9]
[4, 5, 8, 9, 2, 7, 3, 6, 1]
[9, 6, 7, 3, 8, 5, 2, 1, 4]
[6, 8, 3, 1, 9, 2, 4, 7, 5]

为了解释这一点,最好从一个简单的顺序索引矩阵开始,其中每行比前一行多偏移一个:

matrix = [ [(r+c)%9 for c in range(9)] for r in range(9) ]

[0, 1, 2, 3, 4, 5, 6, 7, 8] # base row
[1, 2, 3, 4, 5, 6, 7, 8, 0] # offset by 1
[2, 3, 4, 5, 6, 7, 8, 0, 1] # offset by 2
[3, 4, 5, 6, 7, 8, 0, 1, 2] # ....
[4, 5, 6, 7, 8, 0, 1, 2, 3]
[5, 6, 7, 8, 0, 1, 2, 3, 4]
[6, 7, 8, 0, 1, 2, 3, 4, 5]
[7, 8, 0, 1, 2, 3, 4, 5, 6]
[8, 0, 1, 2, 3, 4, 5, 6, 7]

如您所见,每一行都有索引0到8(因此没有重复),每一列也有索引0到8,因为偏移而没有重复。你知道吗

现在,如果我们创建一个从1到9的数字列表并对其进行无序排列,我们可以用无序排列列表中相应的数字替换矩阵中的索引。由于每个索引映射到不同的数字,因此生成的矩阵在行或列上不会有任何重复。你知道吗

numbers = random.sample(range(1,10),9) # [1, 5, 9, 8, 3, 7, 6, 2, 4]
matrix  = [ [numbers[i] for i in row] for row in matrix ]

[1, 5, 9, 8, 3, 7, 6, 2, 4]
[5, 9, 8, 3, 7, 6, 2, 4, 1]
[9, 8, 3, 7, 6, 2, 4, 1, 5]
[8, 3, 7, 6, 2, 4, 1, 5, 9]
[3, 7, 6, 2, 4, 1, 5, 9, 8]
[7, 6, 2, 4, 1, 5, 9, 8, 3]
[6, 2, 4, 1, 5, 9, 8, 3, 7]
[2, 4, 1, 5, 9, 8, 3, 7, 6]
[4, 1, 5, 9, 8, 3, 7, 6, 2]

最后,我们可以洗牌的行得到一个更随机的组织矩阵

random.shuffle(matrix)

[5, 9, 8, 3, 7, 6, 2, 4, 1]
[9, 8, 3, 7, 6, 2, 4, 1, 5]
[1, 5, 9, 8, 3, 7, 6, 2, 4]
[7, 6, 2, 4, 1, 5, 9, 8, 3]
[2, 4, 1, 5, 9, 8, 3, 7, 6]
[6, 2, 4, 1, 5, 9, 8, 3, 7]
[4, 1, 5, 9, 8, 3, 7, 6, 2]
[8, 3, 7, 6, 2, 4, 1, 5, 9]
[3, 7, 6, 2, 4, 1, 5, 9, 8]

以及列:

cols   = random.sample(range(9),9) # [7, 4, 3, 0, 8, 1, 2, 5, 6]
matrix = [[matrix[r][c] for c in cols] for r in range(9)]

[4, 7, 3, 5, 1, 9, 8, 6, 2]
[1, 6, 7, 9, 5, 8, 3, 2, 4]
[2, 3, 8, 1, 4, 5, 9, 7, 6]
[8, 1, 4, 7, 3, 6, 2, 5, 9]
[7, 9, 5, 2, 6, 4, 1, 8, 3]
[3, 5, 1, 6, 7, 2, 4, 9, 8]
[6, 8, 9, 4, 2, 1, 5, 3, 7]
[5, 2, 6, 8, 9, 3, 7, 4, 1]
[9, 4, 2, 3, 8, 7, 6, 1, 5]

解决方案(如上)将这些步骤合并到一个列表理解中,但使用完全相同的方法。你知道吗

使用这种方法,也可以产生一个随机数独板(与3x3块约束)。偏移量的公式要复杂一些,行和列的洗牌只能在块组内部和块组之间进行,但总体技术是相同的。你知道吗

from random import sample
base  = 3  # Will generate any size of random sudoku board instantly
side  = base*base
nums  = sample(range(1,side+1),side) # random numbers
board = [[nums[(base*(r%base)+r//base+c)%side] for c in range(side) ] for r in range(side)]
rowGr = sample(range(base),base) # random rows/horizontal blocks
rows  = [ r for g in rowGr for r in sample(range(g*base,(g+1)*base),base) ] 
colGr = sample(range(base),base) # random column/vertical blocks
cols  = [ c for g in colGr for c in sample(range(g*base,(g+1)*base),base) ]            
board = [[board[r][c] for c in cols] for r in rows]

for line in board:print(line)
[7, 5, 3, 6, 9, 4, 1, 2, 8]
[6, 9, 4, 1, 2, 8, 7, 5, 3]
[1, 2, 8, 7, 5, 3, 6, 9, 4]
[2, 8, 7, 5, 3, 6, 9, 4, 1]
[5, 3, 6, 9, 4, 1, 2, 8, 7]
[9, 4, 1, 2, 8, 7, 5, 3, 6]
[8, 7, 5, 3, 6, 9, 4, 1, 2]
[3, 6, 9, 4, 1, 2, 8, 7, 5]
[4, 1, 2, 8, 7, 5, 3, 6, 9]

这将在0.2毫秒内生成一个随机的9x9数独,而试错法需要1到20秒(非常随机的时间)

与拉丁方技术一样,这是基于一个有效的基线板,该基线板由具有适当行、列和块约束的索引组成:

base  = 3
side  = base*base
board = [[(base*(r%base)+r//base+c)%side for c in range(side)] for r in range(side)]

for line in board: print(line)

[0, 1, 2, 3, 4, 5, 6, 7, 8] # base row
[3, 4, 5, 6, 7, 8, 0, 1, 2] # offset by 3
[6, 7, 8, 0, 1, 2, 3, 4, 5] # offset by 6
[1, 2, 3, 4, 5, 6, 7, 8, 0] # offset by 1
[4, 5, 6, 7, 8, 0, 1, 2, 3] # offset by 4
[7, 8, 0, 1, 2, 3, 4, 5, 6] # offset by 7
[2, 3, 4, 5, 6, 7, 8, 0, 1] # offset by 2
[5, 6, 7, 8, 0, 1, 2, 3, 4] # offset by 5
[8, 0, 1, 2, 3, 4, 5, 6, 7] # offset by 8

其余的仅仅是用乱序数字替换索引,以及行、列和块的乱序。你知道吗

相关问题 更多 >