无法验证列中是否已存在数字

时间:2019-06-25 19:14:38

标签: 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])

2 个答案:

答案 0 :(得分:0)

忘记索引循环,除非您需要索引用于其他目的。包含列表推导和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 放在第二位的任意位置。

等等;将其公式化为一般情况,您当前的算法就更容易了。使用集合而不是列表会有所帮助。

答案 1 :(得分:0)

您可以维护一组使用的列值的列表。新“改组”行的验证可以更直接地完成。对于子矩阵组也是如此,尽管您需要使用间接(或复杂的索引计算)将位置映射到组集:

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

其余的只是用改编的数字替换索引以及改写行的列和块。