【QuotationTool】主要数据结构
項目鏈接:https://gitee.com/xyjtysk/quotationTools
采用什么樣的數(shù)據(jù)結(jié)構(gòu)
那么我們希望讀出來的數(shù)據(jù)是這個什么樣子呢?也就是數(shù)據(jù)結(jié)構(gòu)是怎么樣的?
既然Excel是個二維表格,那么讀出來的數(shù)也放在一個二維表格里面得了。
我們一個簡化版的例子來看,下面的表格是從原始表格中截出來的一部分。
| 0235A0W2 | RT-MSR5660 | 2 | 50000 |
這樣的缺點在于:取每個元素,需要計算index,不方便編程。
比如我們要取第三行的“RT-MSR5660”,我們需要使用a[1][1]來取,非常不方便。
我們知道最方便取的數(shù)據(jù)結(jié)構(gòu)為dict,只要傳進(jìn)去一個key,它就會返回一個value,這樣的好處是
可以為每一列賦予實際的含義,比如說可以把產(chǎn)品型號的key設(shè)為BOM,我們要取“RT-MSR5660”的時候,就可以用a[1]['BOM']
如果要調(diào)換列的順序,可以輕松做到,更為的靈活
因為每一列賦予了實際的含義,我們根本不用擔(dān)心具體的順序
那么具體的數(shù)據(jù)格式應(yīng)該是怎么樣的呢?
首先我們?yōu)樗苡玫降牧蟹峙湟粋€key值,映射表格如下:
| ID | ID |
| 產(chǎn)品編碼 | BOM |
| 產(chǎn)品型號 | typeID |
| 項目名稱 | description |
| 單套數(shù)量 | quantity |
| 目錄價 | unitsNetListPrice |
| 折扣 | discount |
| 單價 | unitsNetPrice |
| 總價 | totalPrice |
| 總目錄價 | totalListPrice |
| 產(chǎn)線 | PL |
| WATSON_LINE_ITEM_ID | waston |
| 備注 | remarks |
那么下面表格所對應(yīng)的數(shù)據(jù)結(jié)構(gòu)可以設(shè)計成這個樣子。
| 0235A0W2 | RT-MSR5660 | 2 | 50000 |
我們來看一下特點:
原始表格中的每一行轉(zhuǎn)換為一個dict
然后把所有行組成一個list
從Excel中讀數(shù)據(jù)
既然現(xiàn)在數(shù)據(jù)結(jié)構(gòu)已經(jīng)設(shè)計好了,我們就來看如何讀數(shù)據(jù),并形成這樣的數(shù)據(jù)結(jié)構(gòu)吧。
首先引入模塊
import xlrd然后定義一個操作類,從excel中讀取數(shù)據(jù)并轉(zhuǎn)換的函數(shù)為getAssociativeArray,需要把Excel的完整路徑傳遞進(jìn)去,以及要讀取的sheet的名稱,還有就是為每列取的key值
class XlrdTool(XlsReader):# 作用:獲取關(guān)聯(lián)數(shù)組# inputHeaderKey:數(shù)組每一列的對應(yīng)的鍵值# 返回:一個數(shù)組,數(shù)組的每一行為一個dict,代表原來表格里面的每一行,其中此dict的鍵名為輸入的inputHeaderKey,鍵值為讀入的excel文件的對應(yīng)值。def getAssociativeArray (self, excelPathName, sheetName , inputHeaderKey):list = []try:sheetList = xlrd.open_workbook(excelPathName).sheet_by_name(sheetName);# row:表示從當(dāng)前sheet讀出了的每一行,# 將每一行的row_values與inputHeaderKey組成dictlist = [dict (zip (inputHeaderKey , sheetList.row_values(row))) for row in range(sheetList.nrows)];except Exception as data:print("打開文件失敗,%s" % data);return list;里面最關(guān)鍵的代碼其實只有:
list = []sheetList = xlrd.open_workbook(excelPathName).sheet_by_name(sheetName);list = [dict (zip (inputHeaderKey , sheetList.row_values(row))) for row in range(sheetList.nrows)];我們來一一看看。
從Excel中的某個sheet里面讀出數(shù)據(jù),xlrd.open_workbook(excelPathName).sheet_by_name(sheetName)
[dict (zip (inputHeaderKey , sheetList .row_values(row))) for row in range(sheetList.nrows)];我們可以拆解一下:
- 這是一個列表生成式,for row in range(sheetList.nrows)表示對讀出來的數(shù)組的每一行 row 進(jìn)行遍歷,
首先使用xlrd中的函數(shù)row_values取出每一行的值
inputHeaderKey表示為每一列賦予的一個key,它是一個數(shù)組。
- 然后使用zip把讀出來的每一行與inputHeaderKey組成鍵值對,再在外面遷套dict形成一個字典。
也就是
所有的dict形成一個列表
總結(jié)一下就是,把為每列分配的key值數(shù)組與每一行進(jìn)行zip,然后轉(zhuǎn)換為dict,最后把所有的dict組成一個list。
數(shù)據(jù)結(jié)構(gòu)的特點
上面講了如何從Excel讀取數(shù)據(jù)形成數(shù)組。
我們再來看一下這種數(shù)據(jù)結(jié)構(gòu)
a = [ {"BOM":"產(chǎn)品編碼", "typeID":"產(chǎn)品型號", "description":"項目名稱", "totalQuantity":"數(shù)量", "unitsNetListPrice":"標(biāo)準(zhǔn)價(RMB)"},{"BOM":"0235A0W2", "typeID":"RT-MSR5660", "description":"H3C MSR 56-60路由器機框", "totalQuantity":"2", "unitsNetListPrice":"50000"} ]它是一個嵌套的數(shù)據(jù)結(jié)構(gòu),總體上是一個list,它有兩個元素,每個元素都是一個dict
那么這個地方就有個坑點了
如果我們再把這個list賦給b,然后在b中把price的價格修改了。
那么list最開始指向的dict并沒有變,沒有指向另一個元素,所以list沒有改變,
但是dict發(fā)生改變了。
也就是a對應(yīng)的那個price也發(fā)生了改變了。
所以我們需要注意,如果把list賦給另一個變量以后,一定要深復(fù)制一份。
如何遍歷
對于我們這個項目來說,遍歷可能是最重要的算法了。首先我們來看一下我們官方給出來的表格吧。
一套配置清單其實有若干套設(shè)備構(gòu)成,每套設(shè)備又有一個子標(biāo)題以及相應(yīng)的詳細(xì)配置信息等,還有小計等。
多套設(shè)備組成了整個清單,
在講遍歷前,我們需要對每個區(qū)域取個名字。
加上colorTag
我們可以把所有行分為如下幾類:
header:表示總的標(biāo)題
site:表示每一套設(shè)備的子標(biāo)題
subtotal:對每一套設(shè)備的小計
total:總計
general:詳細(xì)配置信息
這幾種他們對應(yīng)的顏色也可以設(shè)為不同的,所以統(tǒng)稱為colorTag
那么怎么在程序中區(qū)分不同的行的類型呢?
我們知道之前設(shè)計的數(shù)據(jù)結(jié)構(gòu)本質(zhì)就是一個list,而每一行是一個dict,所以只需要再加一個鍵值對即可,比如總計行就加上"colorTag":"total"即可。
之前讀取Excel數(shù)據(jù)的時候并沒有加上這個ColorTag,那么現(xiàn)在要加的話,需要對整個list進(jìn)行一次遍歷,識別每一行的特征,加上相應(yīng)的colorTag
aDiff = [i for i in ['BOM','typeID','description'] if i in self.lists[0].keys()]; colTag = aDiff[0]; for aList in self.lists:if aList[colTag] == "小計":aList['colorTag'] = "subtotal";elif aList[colTag] == "總計":aList['colorTag'] = "total";elif aList['ID'] != "":aList['colorTag'] = 'site';else:aList['colorTag'] = "general";self.lists[0]['colorTag'] = "header"解釋一下代碼:
首先colTag指的是'BOM','typeID','description'這幾個誰存在,則取誰為colTag
然后遍歷數(shù)組的每一行,如果aList[colTag]="小計"或者蹤跡的時候,就可以判斷出是小計行或者總計行
另外我們觀察得到ID列除了子標(biāo)題site對應(yīng)的行有值,其他的行都是空的,所以可以使用aList['ID'] != ""來判斷哪些是site行
第一行就是header行
剩下的自然是general
我們還可以再遍歷一次新生成的list,然后把colorTag為site的那些行的序號取出來,這就可以確定每一套設(shè)備的起始和截止的位置了。
轉(zhuǎn)載于:https://www.cnblogs.com/dy2903/p/8466604.html
總結(jié)
以上是生活随笔為你收集整理的【QuotationTool】主要数据结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [LeetCode]547. Frien
- 下一篇: .net 零碎点梳理