Python进阶:丢失的一笔订单
- 2019 年 12 月 26 日
- 筆記
2018年某天曾接到一个需求,要求给10个监考老师监考的10个科目来分配考场,要求每个老师的监考考场不能重复。见下图,不知道你感觉怎么样,我当时搞了几天没有找出随机生成的方法,丢失了一笔订单。

既然咱们已经学习了python,不妨用python试试。
需求分析:
1、生成一个10*1的数组;使用numpy.arange
2、随机排序;使用random.shuffle
3、如果一个10*1的数组到这里就完事了,可是题目要求的是10*10,没有现成的函数可以生成10*10,且行和列各不相等的矩阵。
4、考虑使用递归,下一次赋值时将已存在值去除(使用set集合)
5、每次赋值时要求随机取一个元素,使用random.sample
import numpy as npimport random # 生成一个10*1 数组arr = np.arange(1, 11, 1)# 将该数组随机排序np.random.shuffle(arr)# 生成一个全部0值的10*10矩阵m = np.zeros((10, 10), int)# 将数组赋值给矩阵的第一行m[0, :] = arr
def calc(i, j): # 设置变量t,存储未出现过的数字,初始值为1~10的集合,第一次要填充 # m[1][0]位置,去除首行首列值就可以了,也就是此时i = 1, j = 0 t = set(np.arange(1, 11)) - set(m[0:1, 0])
# 从集合t中随机取一个元素赋值给m[1][0]x = random.sample(t, 1)

# 刚才赋值时用到的元素需要在集合t中剔除,否则会重复出现t.remove(int(x[0]))# 至此,第一次赋值就结束了,考虑继续赋值m[1][1],将列编号变量j+1,步骤相同# 数字1~10的集合,去除首行1列的值也就是去除m[0][1]t = set(np.arange(1, 11)) - set(m[0:1, 1]) # i=1,j=1# 同时,还需要去除1行0列的值,也就是m[1][0]t = t - set(m[1, 0:1]) # i=1,j=1

# 从集合t中随机取一个元素赋值给m[1][1]x = random.sample(t, 1)

# 同理,此时需要将刚才赋值时用到的元素在集合t中剔除t.remove(int(x[0]))# 至此,第二次赋值就结束了,考虑继续赋值m[1][2],将列编号变量j+1,步骤相同# 第二行赋值完了,赋值第三行。。。# 直到赋值到第9行第9列,否则一直循环运行。......
分析两次赋值的规律,抽象出calc函数如下:
def calc(i, j): t = set(np.arange(1, 11)) - set(m[0:i, j]) # t是未出现数字的集合:数字1~10,去除首行至i-1 行,j列的已出现值 t = t - set(m[i, 0:j]) # 去除i行,j-1列的已出现值,经过行列去重,t是未出现数字的集合 while True: if len(t) == 0: return False x = random.sample(t, 1) # 集合t中随机截取一个长度为1的切片 m[i][j] = x[0] # 将切片的元素值赋值给i行j列 t.remove(int(x[0])) # 集合t去除刚才的赋值 if j < 9: if calc(i, j + 1): return True elif i < 9: if calc(i + 1, 0): return True else: return True
我们来看看某次代码运行结果吧。(每运行一次结果不同)

小伙伴们可以试试,你是否可以得出10*10的矩阵,要求是行和列都不能相同。