我有一个矩阵或列表列表:
x = [[1,2,3],
[2,3,1],
[3,1,2]]
我的目标是检查是否
1)矩阵的每一列都包含从1到n的整数中的每一个。
2)矩阵的每一行都包含从1到n的整数中的每一个。
这是我在解决Udacity编程课程介绍时遇到的问题练习。这是我解决问题的方法。我知道这是漫长而低效的。那么解决这个问题的简短而有效的方法是什么?
def check(p):
j = 0
for e in p:
i = 1 + j
s = str(p)
if s.find('.')!= -1:
return False
while i < len(p):
if p[i] == e:
return False
if p[i] > len(p) or p[i] < 1:
return False
i += 1
j += 1
return True
def check_sudoku(p):
i = 0
z = []
a = []
x = 0
for e in p:
r = check(e)
if r == False:
return r
#Below here is to transpose the list
while x < len(p):
z.append(1)
x += 1
while i < len(p):
for e in p:
a.append(e.pop())
z[i] = a
i += 1
a = []
#Below here is to check the transpose
for g in z:
r = check(g)
if r == False:
return r
return True
答案 0 :(得分:4)
您可以像这样简化检查程序:
def check_valid(matrix):
n = len(matrix[0])
valid_num = range(1, n+1) # make a list of valid number from 1 to n
# sort rows and column of matrix in ascending order and compare with valid_num
for line in matrix:
if sorted(line) != valid_num:
return False
for column in zip(*matrix):
if sorted(column) != valid_num:
return False
# If all rows and column is valid, then
return True
编辑:关注@vocalno KISS规则,但速度更快,适用于数字和字符
def check_valid2(matrix):
n = len(matrix)
for line in matrix+zip(*matrix):
if len(set(line)) != n:
return False
return True
In[9]: %timeit for m in (x, y): check_valid_mine(m)
100000 loops, best of 3: 8.55 µs per loop
In[10]: %timeit for m in [x,y]: check_valid2(m)
100000 loops, best of 3: 5.77 µs per loop
编辑2:所有关于速度
def check_valid3(matrix):
n = len(matrix)
for line in matrix+zip(*matrix):
if not len(set(line)) - n:
return False
return True
In[19]: %timeit for m in [x,y]: check_valid3(m)
100000 loops, best of 3: 2.29 µs per loop
答案 1 :(得分:2)
这是我的解决方案
我在行和列上循环,使用 zip 翻转矩阵和链 - 组合2个列表。 如果行或列包含的值不在 valid_set ,
中set(row) - valid_set
表达式将产生非空集 - 由而不是转为 False - 并且所有循环将结束
from itertools import chain
def check_valid(matrix, n):
valid_set = set(range(1, n+1))
return all(not(set(row) - valid_set) for row in chain(matrix, zip(*matrix)))
修改强>
对不起,误读了这个问题;这是正确的答案 - 所有退出第一个 False
from itertools import chain
def check_valid(matrix):
valid_set = set(range(1, len(matrix)+1))
return all(set(row) == valid_set for row in chain(matrix, zip(*matrix)))
编辑2:
出于好奇 - 我定时排序 vs 设置方法
In [74]: x = [[1,2,3],
....: [2,3,1],
....: [3,1,2]]
In [79]: %timeit for row in x: sorted(row)
1000000 loops, best of 3: 1.38 us per loop
In [80]: %timeit for row in x: set(row)
1000000 loops, best of 3: 836 ns per loop
设置的速度提高了约30%
编辑3: 我修复了dangerous解决方案并更新了我的
In [132]: def check_valid(matrix):
valid_num = np.unique(np.array(matrix)).tolist() # selects unique elements
for line in matrix:
if sorted(line) != valid_num:
return False
for column in zip(*matrix):
if sorted(column) != valid_num:
return False
return True
In [136]: %timeit for m in (z, d): check_valid(m)
10000 loops, best of 3: 57.8 us per loop
In [115]: def check_valid_mine(matrix):
valid_set = set(chain(*matrix))
return all(set(row) == valid_set for row in chain(matrix, zip(*matrix)))
In [137]: %timeit for m in (z, d): check_valid_mine(m)
100000 loops, best of 3: 8.96 us per loop
底线?吻 - 保持简单愚蠢
通过zip()
解释矩阵转置运算符在函数调用中的iterable参数之前扩展了这个位置参数的参数列表,基本上是
拉链(*矩阵)
装置
zip(matrix[0], matrix[1], matrix[2], ...)
从而将列重新排列成行 查看this answer以获取*和**运算符的详细说明
答案 2 :(得分:0)
我正在寻找一个完全匹配字符和数字的解决方案,我带来了一个使用numpy库的解决方案。我略微修改了dragon2fly解决方案。如果我错了,请纠正我。我检查了z和d值的解决方案,并给出了正确的结果。
import numpy as np
z = [[8,9,10], # example case with numbers
[9,10,8],
[10,8,9]]
d = [['a','b','c'], # example case with characters
['b','c','a'],
['c','a','b']]
def check_valid(matrix):
valid_num = list(np.unique(matrix)) # selects unique elements
# sort rows and column of matrix in ascend order and compare with valid_num
for line in matrix:
if sorted(line) != valid_num:
return False
for column in zip(*matrix):
if sorted(column) != valid_num:
return False
# If all rows and column is valid, then
return True