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
至此,第一行已經按照要求生成了,現在從m[1,0]開始給剩餘的0賦值。定義一個計算函數calc(i, j) #i, j分別表示行列編號
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的矩陣,要求是行和列都不能相同。