• 【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的那些行的序号取出来,这就可以确定每一套设备的起始和截止的位置了。

  • 相关阅读:
    android 6.0 以上在doze模式精确定时
    MySQL 性能优化神器 Explain 使用分析
    android java层通过jni加载使用第三方的so库
    android 抓取native层奔溃
    mybatis面试入门
    Python实现异步 io多种方式
    可用率map处理
    雷哥带你走进Javascript
    前端存储技术
    听雷哥浅谈Redis
  • 原文地址:https://www.cnblogs.com/dy2903/p/8466604.html
Copyright © 2020-2023  润新知