有些场景使用多维哈希来存储数据,时间复杂度恒定,简单粗暴好用。这里记录一下。
如下是三维哈希的简单示意图,建议层数不要太多,否则时间久了,自己写的代码都不认识。
下图是三维哈希在内存的存储形式,hashmap嵌套了3层。图里一层数组存放entry和链表next指针,每个节点里面都存放一个数组,数组存放下一层hashcode和下一层链表指针。(没有将哈希分桶链表完整画出来,本图重点是哈希嵌套)
这个数据结构我是用来解析保存不同设备的配置,每个设备有两个配置文件。当新来一个该设备的数据(base64加密后的json序列化字符串),通过这个三维哈希层层解析,返回给用户直观的表象。这里不谈业务,只谈如何暴力存,暴力解。
/***************************************************************************** 结 构 名 : StringStu 功能描述 : 设备string文件数据结构 *****************************************************************************/ type StringStu struct { Cat_name string `json:"cat_name,omitempty"` Dev_name string `json:"dev_name,omitempty"` Pid string `json:"pid,omitempty"` Error interface{} `json:"error,omitempty"` Intfs interface{} `json:"intfs,omitempty"` Vendor_name string `json:"vendor_name,omitempty"` } /***************************************************************************** 结 构 名 : 产品string文件相关处理 功能描述 : *****************************************************************************/ func GetAllProductString() (Slice []ProfileSuidsStu) { StringStu := ReadStringFile() for _, StringOne := range StringStu { LoadDevStrings2Cache(StringOne.Pid, libf.StructToJsonStringOne(StringOne.Intfs)) } return } func ReadStringFile() []StringStu { var file string = "" var StringSlice = make([]StringStu, 0) file = libf.KeyfileT(file).GetFileName("strings.json") Byte, Error := ioutil.ReadFile(file) if Error != nil { prnLog.LogPrint(libf.LOG_ERROR, 0, false, false, "", "ReadFile error", Error) return nil } msg, ret := libf.ParseJsonByStructMsg(Byte, &StringSlice) return StringSlice } /***************************************************************************** 结 构 名 : StringIntfsStu 功能描述 : 设备string文件,设备Intfs属性 *****************************************************************************/ type StringsIntfsStu struct { Name string `json:"name,omitempty"` //字段的中文名称,例如:电量,背景灯光 Unit string `json:"unit,omitempty"` //单元,例如温度°C Values map[string]string `json:"values,omitempty"` //字段值对应的中文枚举,例如:0是关,1是开 } type ParamAttr = map[string]StringsIntfsStu var ProductStrings = make(map[string](ParamAttr), 0) /***************************************************************************** * \author pxx * \date 2018/08/25 * \brief 将所有设备的strings配置,载入一个三维哈希中。 一维哈希是ProductStrings,key为pid, 二维哈希是ParamAttr,key为字段英文名称, 三维哈希是StringIntfsStu结构体内的Values,key为字段的值 * \param[in] * \param[out] * \return * \ingroup * \remarks ******************************************************************************/ func LoadDevStrings2Cache(pid, String string) { var ( keyListString map[string]interface{} = make(map[string]interface{}, 0) _param_attr = make(ParamAttr, 0) ) ProductStrings[pid] = _param_attr msg, ret := libf.ParseJsonByStructMsg([]byte(String), &keyListString) for key, value := range keyListString { var string1 StringsIntfsStu //注意作用域 msg, ret = libf.ParseJsonByStructMsg([]byte(libf.StructToJsonStringOne(value)), &string1) if ret != libf.Success { prnLog.LogPrint(libf.LOG_DEBUG, 0, false, false, "msg=%v,ret=%v", msg, ret) continue } _param_attr[key] = string1 } }
上面的代码是粗暴的将所有设备的配置文件存入内存,下面则是根据这个三维哈希去解析数据。
/***************************************************************************** * \author pxx * \date 2018/08/27 * \brief 将json序列化的无结构数据,映射为结构化数据 * \param[in] * \param[out] * \return * \ingroup * \remarks 开源代码说明:https://www.jb51.net/article/73996.htm ******************************************************************************/ func FormatUploadData(StringData string) (StructData StructUploadDataStu) { StructData.Did = gojson.Json(StringData).Get("did").Tostring() StructData.Pid = gojson.Json(StringData).Get("pid").Tostring() for k, v := range ProductProfile[StructData.Pid] { //k是字段名称,v是这个字段的子属性 value := gojson.Json(StringData).Get(k).Tostring() //根据设备每个字段的不同属性,来映射对应的中文名称,枚举值,字符串值还有整数值 switch v.In[0] { case 1, 3: //1表示枚举,2表示是连续型的参数,3 string StructData.Data += ProductStrings[StructData.Pid][k].Name + ":" + ProductStrings[StructData.Pid][k].Values[value] + ", " case 2: StructData.Data += ProductStrings[StructData.Pid][k].Name + ":" + value + ", " default: } } return }