zoukankan      html  css  js  c++  java
  • 【QuotationTool】主要数据结构

    项目链接:https://gitee.com/xyjtysk/quotationTools

    采用什么样的数据结构

    那么我们希望读出来的数据是这个什么样子呢?也就是数据结构是怎么样的?

    既然Excel是个二维表格,那么读出来的数也放在一个二维表格里面得了。

    我们一个简化版的例子来看,下面的表格是从原始表格中截出来的一部分。

    产品编码 产品型号 数量 标准价(RMB)
    0235A0W2 RT-MSR5660 2 50000

    这样的缺点在于:取每个元素,需要计算index,不方便编程。

    比如我们要取第三行的“RT-MSR5660”,我们需要使用a[1][1]来取,非常不方便。

    我们知道最方便取的数据结构为dict,只要传进去一个key,它就会返回一个value,这样的好处是

    • 可以为每一列赋予实际的含义,比如说可以把产品型号的key设为BOM,我们要取“RT-MSR5660”的时候,就可以用a[1]['BOM']

    • 如果要调换列的顺序,可以轻松做到,更为的灵活

      因为每一列赋予了实际的含义,我们根本不用担心具体的顺序

    那么具体的数据格式应该是怎么样的呢?

    首先我们为所能用到的列分配一个key值,映射表格如下:

    NHCT中的列 key值
    ID ID
    产品编码 BOM
    产品型号 typeID
    项目名称 description
    单套数量 quantity
    目录价 unitsNetListPrice
    折扣 discount
    单价 unitsNetPrice
    总价 totalPrice
    总目录价 totalListPrice
    产线 PL
    WATSON_LINE_ITEM_ID waston
    备注 remarks

    那么下面表格所对应的数据结构可以设计成这个样子。

    产品编码 产品型号 数量 标准价(RMB)
    0235A0W2 RT-MSR5660 2 50000
    [
    {"BOM":"产品编码",    
    "typeID":"产品型号",    
    "description":"项目名称",    
    "totalQuantity":"数量",    
    "unitsNetListPrice":"标准价(RMB)"},
    
    {"BOM":"0235A0W2",    
    "typeID":"RT-MSR5660",   
    "description":"H3C MSR 56-60路由器机框",   
    "totalQuantity":"2",    
    "unitsNetListPrice":"50000"}
    ]
    

    我们来看一下特点:

    • 原始表格中的每一行转换为一个dict

    • 然后把所有行组成一个list
      image.png

    从Excel中读数据

    既然现在数据结构已经设计好了,我们就来看如何读数据,并形成这样的数据结构吧。

    首先引入模块

    import xlrd
    

    然后定义一个操作类,从excel中读取数据并转换的函数为getAssociativeArray ,需要把Excel的完整路径传递进去,以及要读取的sheet的名称,还有就是为每列取的key值

    class XlrdTool(XlsReader):
        # 作用:获取关联数组
        # inputHeaderKey:数组每一列的对应的键值
        # 返回:一个数组,数组的每一行为一个dict,代表原来表格里面的每一行,其中此dict的键名为输入的inputHeaderKey,键值为读入的excel文件的对应值。
        
        def getAssociativeArray (self, excelPathName, sheetName , inputHeaderKey):
            list = []
            try:
                sheetList = xlrd.open_workbook(excelPathName).sheet_by_name(sheetName);
                # row:表示从当前sheet读出了的每一行,
                # 将每一行的row_values与inputHeaderKey组成dict
                list = [dict (zip (inputHeaderKey , sheetList
                .row_values(row))) for row in range(sheetList.nrows)];
                
            except Exception as data:
                print("打开文件失败,%s" % data);
            return list;
    

    里面最关键的代码其实只有:

    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里面读出数据,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)表示对读出来的数组的每一行 row 进行遍历,

      对其中某一行row

      • 首先使用xlrd中的函数row_values取出每一行的值

      • inputHeaderKey表示为每一列赋予的一个key,它是一个数组。

      • 然后使用zip把读出来的每一行与inputHeaderKey组成键值对,再在外面迁套dict形成一个字典。
        也就是

    {"BOM":"0235A0W2",    
    "typeID":"RT-MSR5660",   
    "description":"H3C MSR 56-60路由器机框",   
    "totalQuantity":"2",    
    "unitsNetListPrice":"50000"}
    
    • 所有的dict形成一个列表

    总结一下就是,把为每列分配的key值数组与每一行进行zip,然后转换为dict,最后把所有的dict组成一个list。

    image.png

    数据结构的特点

    上面讲了如何从Excel读取数据形成数组。

    我们再来看一下这种数据结构

    a = [
    {"BOM":"产品编码",    
    "typeID":"产品型号",    
    "description":"项目名称",    
    "totalQuantity":"数量",    
    "unitsNetListPrice":"标准价(RMB)"},
    
    {"BOM":"0235A0W2",    
    "typeID":"RT-MSR5660",   
    "description":"H3C MSR 56-60路由器机框",   
    "totalQuantity":"2",    
    "unitsNetListPrice":"50000"}
    ]
    

    它是一个嵌套的数据结构,总体上是一个list,它有两个元素,每个元素都是一个dict

    image.png

    那么这个地方就有个坑点了

    如果我们再把这个list赋给b,然后在b中把price的价格修改了。

    image.png

    那么list最开始指向的dict并没有变,没有指向另一个元素,所以list没有改变,

    但是dict发生改变了。

    也就是a对应的那个price也发生了改变了。

    所以我们需要注意,如果把list赋给另一个变量以后,一定要深复制一份。

    image.png

    如何遍历

    对于我们这个项目来说,遍历可能是最重要的算法了。首先我们来看一下我们官方给出来的表格吧。

    一套配置清单其实有若干套设备构成,每套设备又有一个子标题以及相应的详细配置信息等,还有小计等。

    多套设备组成了整个清单,

    image.png

    在讲遍历前,我们需要对每个区域取个名字。

    加上colorTag

    我们可以把所有行分为如下几类:

    • header:表示总的标题

    • site:表示每一套设备的子标题

    • subtotal:对每一套设备的小计

    • total:总计

    • general:详细配置信息

    image.png

    这几种他们对应的颜色也可以设为不同的,所以统称为colorTag

    那么怎么在程序中区分不同的行的类型呢?

    我们知道之前设计的数据结构本质就是一个list,而每一行是一个dict,所以只需要再加一个键值对即可,比如总计行就加上"colorTag":"total"即可。

    之前读取Excel数据的时候并没有加上这个ColorTag,那么现在要加的话,需要对整个list进行一次遍历,识别每一行的特征,加上相应的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

    • 然后遍历数组的每一行,如果aList[colTag]="小计"或者踪迹的时候,就可以判断出是小计行或者总计行

    • 另外我们观察得到ID列除了子标题site对应的行有值,其他的行都是空的,所以可以使用aList['ID'] != ""来判断哪些是site行

    • 第一行就是header行

    • 剩下的自然是general

    我们还可以再遍历一次新生成的list,然后把colorTag为site的那些行的序号取出来,这就可以确定每一套设备的起始和截止的位置了。

  • 相关阅读:
    HDU 1102 Constructing Roads
    HDU 1285 确定比赛名次。
    最小生成树 HDU 各种畅通工程的题,prim和kru的模板题
    HDU Jungle Roads 1301 最小生成树、
    并查集小结(转)
    HDU hdu 2094 产生冠军 拓扑排序 判定环
    模运算(转)
    拓扑排序(主要是确定环和加法) HDU 2647 Reward
    HDU 1372 Knight Moves 简单BFS
    用计算机模型浅析人与人之间沟通方式 (一)如何谈话
  • 原文地址:https://www.cnblogs.com/dy2903/p/8466604.html
Copyright © 2011-2022 走看看