Lua表存储优化

一览

问题

在研发过程中,通常会定义一些Excel表格,规定行列值让策划填写,然后,转成lua的table文件,直接使用。

但是,随着研发进行,项目迭代,表格将越来越大。

如果表格中存在大量重复数据,或者表格中很多列数值重复,则可以通过数据压缩给表减减肥。

解决

利用python实现lua表的数据压缩

  • excel表内存在大量 同列不同行 内容一致
  • excel表内存在大量 复合型 单元格内容一致

具体代码,均在github中: ltree98’s github -> CompressLua




参照方案

这是我在网上看到的文章:

Lua配置表存储优化方案

总结的来说,就是

  • 利用lua的元表机制。如果在table中取的值不存在,会去它的元表中查找(如果元表存在)。
  • 将重复的table,提取出来,将所有使用的地方引用过去。



问题

在参照方案的文章中,也提供了解决方法,但是在使用过程中遇见一些问题。

对同一文件压缩后文件MD5可能不一致

对同一个lua文件,进行减肥,在减肥后,虽然最终体重一样,但是可能这次瘦了肚子,下次瘦了腿。

主要原因就是参照方案使用lua处理,对同一个table遍历顺序是不稳定的,即table中存在 A B C 元素,可能这次遍历顺序是 A-B-C,下次遍历顺序可能就是 B-A-C;稳定性得不到保证。

lua的官网对于table的遍历描述一直是:

The order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numeric order, use a numerical for or the ipairs function.)

就是 索引在遍历过程中的次序是不固定的,即使是数字索引也不固定。

因为,项目中使用热更机制是比较两个文件的MD5,决定是否更新该文件。

所以,这个问题就显得很严重,每次热更要更新所有的表。当然,这个问题也可以通过做备份等方式来弥补,但是毕竟治标不治本。

但是用不同的lua版本发现:

使用 lua5.1 版本 生成的压缩文件是一致的

使用 lua5.3版本 生成的压缩文件是不一致的



复杂度高

虽然是现成的,但是也没法直接拿来用;

还是要根据项目现状进行修改。

在整合过程中,发现逻辑比较复杂,而且工具集与我们现有的python不符。(如果用其他工具集,又要去配置相应环境等,比较麻烦)。




修改方案

简介

目的

  • 解决 Excel表 内存在大量 同列不同行 内容一致
  • 解决 Excel表内存在大量 复合型单元格 内容一致

设计

  • 对于重复table,只存一份,其他引用过去
  • 设计一个基础元表,存储Excel每列 最频繁的值;其他表缺省 最频繁的值
  • 设置 只读属性

注意

  • Lua作用域内存放最大的local变量个数为 200个,超过的需要放入临时数组
  • 输出到lua文件,key值不可存在特殊字符($、- 等)

缺点

  • Lua表的可读性变差,需要跳转获取最终值
  • 使用元表实现,若后续处理(比如 加密,修改操作 等)也存在使用元表,增加处理的复杂度


方案

名词解释

  • Excel表:Excel转换成Lua的表,一般结构为

    -- tableName.lua
    
    local tableName = {
        ...
    }
    return tableName
    
  • 默认表:未来的元表,存储Excel中每列最频繁的元素

  • 重复表:Excel表中各单元格重复的 复合型元素(array/table)


流程

  1. 遍历表,进行统计

    • 统计Excel表中各列元素出现次数

    • 统计Excel表中 单元格复合型元素 出现次数

  2. 构造 重复表

    • 筛选 单元格复合型元素 次数大于1的元素,构建重复表
  3. 构造 默认表

    • 根据各列最频繁元素,构造默认表
  4. 整理 Excel表

    • 根据默认表,将重复的字段忽略
  5. 输出 各表

    • 根据 重复表,替换并输出 重复表
    • 根据 重复表,替换并输出 Excel表
    • 根据 重复表,替换并输出 默认表
  6. 设置 元表 及 只读属性


关键代码

最新代码请移步 lt-tree的github

###################################################################
##
##  tools
##

def count_dict_deep(dict_temp):
	"""Count dictionary's deep

		Args:
			dict_temp: dict

		Returns:
			int : deep
	"""

    deep = 0
    for item in dict_temp.values():
        if isinstance(item, dict):
            temp_deep = count_dict_deep(item)
            if temp_deep > deep:
                deep = temp_deep

    return deep+1

def calc_weight(obj1):
	"""Calculate obj's weight

		Args:
			obj1: tuple[dict's string, dict's frequency]
		
		Returns:
			int : weight
	"""

    dict1 = eval(obj1[0])
    times1 = obj1[1]

    deep1 = count_dict_deep(dict1)
    ans = deep1 + 1/times1

    return ans

def count_table_frequency(unit_dict, dict_frequency):
    """Count table frequency
        
        Count table frequency and record as {table string: times}

        Args:
            unit_dict: dict, need analyse data
            dict_frequency: dict, the record's set
    """

    unit_str = str(unit_dict)
    if unit_str in dict_frequency:
        dict_frequency[unit_str] = dict_frequency[unit_str] + 1
    else:
        dict_frequency[unit_str] = 1

    # traversing sub dict
    for item in unit_dict.values():
        if isinstance(item, dict):
            count_table_frequency(item, dict_frequency)


def count_table_value_frequency(key, value, item_frequency):
    """Count table value frequency

        Count every excel column element appear times.
        Record as {
                    key1 : {element1 : times, element2: times, ...}
                    key2 : {element1 : times, element2: times, ...}
                    ...
                    }

        Args:
            key: string
            value: string or dict
            item_frequency: dict, the record's set
    """

    if isinstance(value, dict):
        value = str(value)

    if key in item_frequency.keys():
        if value in item_frequency[key].keys():
            item_frequency[key]
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值