Python实现多键字典

news2024/11/15 13:38:01

实现背景

在许多场景中,有时需要通过多种信息来获取某个特定的值,而各种编程语言(包括Python)使用的字典(Dict)数据结构通常只支持单个键值寻值key-val对,即“一对一”(一个键对应一个值)。而“多对一”的字典在复杂信息映射下有很高实用价值。例如:

在实现非确定性下推自动机的时候,转移函数出现下面的形式:
δ ( q , X ) = { ( p , Z ) } 。 \delta(q,X) = \{(p,Z)\}。 δ(q,X)={(p,Z)}
如果采用“一对一”字典的形式,那么只能以 q q q作为键(key), ( X , p , Z ) (X,p,Z) (X,p,Z)的集合作为其对应的值(val)。即dict[q] = {(X,p,Z)}。这样在访问和设置值的时候,遍历的复杂度显然增加了。

显然我们更希望采用形如d[q][X]={(p,Z)}的形式,以q,X作为一对键值去访问和获取(p,Z)对。这就希望有一种数据结构能够实现“多对一”的访问。

为此,可以设计“多键字典”来满足该要求。即对于一个键的个数为 n n n的多键字典 D D D,它可以通过:
D [ k e y 1 ] [ k e y 2 ] . . . [ k e y n ] D[key_1][key_2]...[key_n] D[key1][key2]...[keyn]
的方式,来获取键值对 ( k e y 1 , k e y 2 , . . . , k e y n ) (key_1,key_2,...,key_n) (key1,key2,...,keyn)所对应的值。

设计思路

有两种方式可以实现上面提到的“多键字典”。

  • 第一种方式是将给定的多键对(multi-keys-pair)转化为一个字符串进行映射:
    对于给定键值对 ( k e y 1 , k e y 2 , . . . , k e y n ) (key_1,key_2,...,key_n) (key1,key2,...,keyn),可以将其转化为一个字符串:key_1,key_2,...key_n(即所有键之间用逗号分隔),然后用已有的字典dict映射即可。注意,键之间一定要有分隔符,如果直接连接起来的话,有可能会造成哈希冲突导致两个不同的多键对被映射到同一处。例如:(aa,b)(a,ab)中的键如果直接连接都会形成aab的字符串,导致哈希冲突。这种方式实现起来比较简单。
  • 第二种方式也是本文所介绍和实现的方式:
    采取”嵌套字典”的作法,这种方法也很容易想到,具体做法如下:
    1. 设置“根字典”。
    2. 对于给定的多键对 ( k e y 1 , k e y 2 , . . . , k e y n ) (key_1,key_2,...,key_n) (key1,key2,...,keyn)和其对应的值 v a l val val,进行映射时按照下面的规则:
      • d = r o o t _ d i c t d = root\_dict d=root_dict
      • 遍历多键对 k e y 1 , k e y 2 , k e y 3 , . . . , k e y n − 1 key_1,key_2,key_3,...,key_{n-1} key1,key2,key3,...,keyn1:
        • 如果 k e y i ( i ≤ n − 1 ) key_i(i\leq n-1) keyi(in1)不在 d d d中,那么令 d [ k e y i ] = n e w _ d i c t d[key_i]=new\_dict d[keyi]=new_dict(否则不需要进行这一步)。然后令 d = d [ k e y i ] d=d[key_i] d=d[keyi](进行字典的嵌套)
      • d [ k e y n ] = v a l d[key_n]=val d[keyn]=val。进行完上一步的的时候, d d d已经指向了“最后一层”字典,这时才真正地对multi_keys~val进行映射。

字典的嵌套如下图所示:
在这里插入图片描述
此外为了方便,需要设置一个集合对多键对进行存储以便之后获取(对应dict.keys())。

代码实现

除了上面介绍的基本原理,还实现了字典的诸如keys(),values(),items()的常用操作,以及对in进行重载等:

import copy
from typing import List,Set,Tuple,Any
class multi_key_dict:
    def __init__(self,key_num = 1) -> None:
        """
        Initialize a multi-key dictionary.
        Args:
            key_num (int, optional):the number of keys. Defaults to 1.
        """
        assert key_num >= 1
        self.__key_num = key_num
        self.__dict = dict()
        self.__keys = set()
        pass

    def set_value(self,keys:tuple,val)->None:
        """Set the value of multi_keys_dict[key_1][key_2]...[key_n].

        Args:
            keys (tuple): A tuple that contains keys in order. Its length must be equal to the number of keys.
            val (_type_): Value.
        """
        assert len(keys) == self.__key_num
        d = self.__dict
        for i in range(0,self.__key_num-1):
            key = keys[i]
            if key not in d:
                d[key] = dict()
            d = d[key]
        d[keys[self.__key_num -1]] = val
        self.__keys.add(keys)        

    def get_value(self,keys:tuple)->Any:
        """Get the value of multi_keys_dict[key_1][key_2]...[key_n].

        Args:
            keys (tuple): A tuple that contains keys in order. Its length must be equal to the number of keys.
        """
        assert len(keys) == self.__key_num
        d = self.__dict
        for i in range(0,self.__key_num):
            d = d[keys[i]]
        return d

    def keys(self)->Set[tuple]:
        """Get all keys of the multi_key_dict.
        """
        return self.__keys.copy()
    
    def values(self)->List[Any]:
        """Get all values of the multi_key_dict.
        """
        values = []
        for key in self.__keys:
            values.append(self.get_value(key))
        return values

    def items(self)->Set[Tuple[Tuple,Any]]:
        """Get set of all "(keys,val)" in multi_keys_dict.
        """
        mutli_keys_dict_items = set()
        for keys in self.__keys:
            val = self.get_value(keys)
            mutli_keys_dict_items.add((keys,val))
        return mutli_keys_dict_items
    
    def __contains__(self,keys:tuple)->bool:
        """Check whether the given multi_keys is in the dict.

        Args:
            keys (tuple): A tuple that contains keys in order. Its length must be equal to the number of keys.

        Returns:
            bool: The result.
        """
        assert len(keys) == self.__key_num
        if keys in self.__keys:
            return True
        return False
    
    def clear(self)->None:
        """Clear all the "keys-val" pairs in the dict.

        Note that the number of keys is not reset.
        """
        self.__dict.clear()
        self.__keys.clear()
    
    def keys_num(self)->int:
        """Get the number of keys.
        """ 
        return self.__key_num
    
    def __str__(self) -> str:
        items = self.items()
        s = str()
        for key,val in items:
            s += f'{key} : {val}\n'
        return s
    
    def copy(self):
        """Return a deep copy of this dict.
        """
        copy.deepcopy(self)

进行测试:

def test_multi_keys_dict():
    d = multi_key_dict(3)
    l = [('a','b','c'),('d','e','f'),('g','h','i'),('g','h','j')]

    # test 'set_value' and 'get_value'
    for i in range(0,len(l)):
        d.set_value(l[i],i)
        assert d.get_value(l[i]) == i
    
    # test 'keys'
    keys = d.keys()
    for elem in l:
        assert elem in keys
    
    # test 'values':
    values = d.values()
    for i in range(0,len(l)):
        assert i in values
    
    # test 'items':
    items = d.items()
    for i in range(0,len(l)):
        assert (l[i],i) in items

    # test 'in':
    for elem in l:
        assert elem in d

    # test 'clear':
    d.clear()
    assert len(d.keys()) == 0

    print('Test passed!')
    
if __name__ == '__main__':
    test_multi_keys_dict()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/391967.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

哈工大服务科学与工程第一章作业

服务的概念服务是个非常广义的概念——涉及到经济、管理、业务、IT领域以下是一些各方对服务的定义:服务是一方向另一方提供的任意活动和好处。它是不可触知的,不形成任何所有权问题,其生产可能与物质产品有关,也可能无关。服务是…

数据挖掘(2.1)--数据预处理

一、基础知识 1.数据的基本概念 1.1基础知识 数据是数据对象(Data Objects)及其属性(Attributes)的集合。 数据对象(一条记录、一个实体、一个案例、一个样本等)是对一个事物或者物理对象的描述。 数据对象的属性则是这个对象的性质或特征,例如一个人的肤色、眼球…

28个案例问题分析---027---单表的11个Update接口--MyBatis

一:背景介绍 项目开发中。我们使用的是MyBatis,在MyBatis的xml文件里,两个表的更新功能,写了足足11个更新接口,毫无复用的思想 这种方式可以正常的实现功能,但是没有复用,无论是从时间上还是维…

推荐系统与推荐算法

文章目录第一章1.1推荐系统意义与价值1.2推荐系统历史与框架1.3推荐算法分类第二章2.1协同过滤的基本思想与分类2.2基于用户的协同过滤2.3基于项目的协同过滤2.4基于邻域的评分预测2.5基于二部图的协同过滤第三章3.1基于关联规则的推荐3.2基于矩阵分解的评分预测3.3概率矩阵分解…

基于jdk8的HashMap源码解析

hashMap常见面试题总览 为什么重写Equals还要重写HashCode方法?HashMap如何避免内存泄漏问题?HashMap1.7底层是如何实现的?HashMapKey为null存放在什么位置?HashMap如何解决Hash冲突问题?HashMap底层采用单链表还是双…

【java基础】泛型程序设计基础

文章目录泛型是什么自定义泛型类自定义泛型方法类型变量的限定总结泛型是什么 泛型类和泛型方法有类型参数,这使得它们可以准确地描述用特定类型实例化时会发生什么。在没有泛型类之前,程序员必须使用Objct编写适用于多种类型的代码。这很烦琐&#xff…

Tuxera NTFS2023MacOS读写软件功能介绍使用

当我们遇到磁盘不能正常使用的情况时本能的会以为是磁盘损坏了,但某些情况下却并非如此。对于mac操作系统来说,软件无法使用设备无法正常读写似乎是很常见的事,毕竟现在的mac电脑对PC机上的产品无法完全适应使用,经常会存在兼容方…

Leetecode 661. 图片平滑器

图像平滑器 是大小为 3 x 3 的过滤器,用于对图像的每个单元格平滑处理,平滑处理后单元格的值为该单元格的平均灰度。 每个单元格的 平均灰度 定义为:该单元格自身及其周围的 8 个单元格的平均值,结果需向下取整。(即&…

Java之可变参数

目录 一.可变参数的引入 1.问题引入 2.可变参数的使用 二.可变参数的注意点 1.可变参数只能定义一个 2.可变参数必须是函数参数的最后一个​编辑 一.可变参数的引入 1.问题引入 当我们需要定义一个方法sum,接受任意个整型变量,结果返回这些整型变量的和. 我们没有学习可…

SCAFFOLD: Stochastic Controlled Averaging for Federated Learning学习

SCAFFOLD: Stochastic Controlled Averaging for Federated Learning学习背景贡献论文思想算法局部更新方式全局更新方式实验总结背景 传统的联邦学习在数据异构(non-iid)的场景中很容易产生“客户漂移”(client-drift )的现象,这会导致系统的收敛不稳定或者缓慢。…

nacos的介绍和下载安装(详细)

目录 一、介绍 1.什么是nacos(含有官方文档)? 2.nacos的作用是什么? 3.什么是nacos注册中心? 4.核心功能 二、下载安装 一、介绍 1.什么是nacos(含有官方文档)? 一个更易于…

libGDX:灯光效果实现一(实现一个点光源)

国内的libGDX文章很少,特别是libGDX实现灯光效果,所以就开始总结灯光效果的实现 绿色的框 是为了方便看到Body位置,使用Box2DDebugRenderer渲染的 工欲善其事,必先利其器,工具集合 gdx-setup.jar 1. 从libGDX官网下载…

GrabCut算法、物体显著性检测

图割GraphCus算法。利用颜色、纹理等信息对GraphCut进行改进,形成效果更好的GrabCut算法。 对图像的目标物体和背景建立一个K维的全协方差高斯混合模型。 其中,单高斯模型的概率密度函数用公式表示为: 高斯混合模型可表示为n个单高斯模型的概…

Java生态/Redis中如何使用Lua脚本

文章目录一、安装LUA1)简单使用二、lua语法简介1、注释1)单行注释2)多行注释2、关键字3、变量1)全局变量2)局部变量4、数据类型1)Lua数组2)字符串操作5、if-else6、循环1)for循环1&g…

Java多线程中的CAS

多线程中的CAS 什么是CAS CAS CompareAndSwap,或者 CompareAndSet, 是一个能够比较和替换的方法。 这个方法能够在多线程环境下保证对一个共享变量进行修改时的原子性不变。 通常,CAS方法会传递三个参数, ● 第一个参数V表示要更新…

核心 Android 调节音量的过程

核心 Android 系统提供的调节音量的方法 核心 Android 系统提供了多种调节音量的方法,这些方法主要包括如下这些。 如在 Android Automotive 调节音量的过程 中我们看到的,CarAudioService 最终在 CarAudioDeviceInfo 中 (packages/services/Car/servi…

RHCSA-文件内容显示(3.6)

查看命令 cat:显示文件内容 cat -n:显示文件内容的同时显示编号 tac:倒叙查看 head 文件名 (默认显示前10行):显示前10行 tail:显示末尾行数信息 more:查看文件信息,从头…

前端基础知识

文章目录前端基础知识HTML1. html基本结构2.常见的html标签注释标签标题标签(h1~h6)段落标签p换行标签 br格式化标签图片标签:img超链接标签表格标签列表标签表单标签input标签label标签select标签textarea 标签盒子标签div&span3. html特殊字符CSS1. 基本语法2…

Hive总结

文章目录一、Hive基本概念二、Hive数据类型三、DDL,DML,DQL1 DDL操作2 DML操作3 DQL操作四、分区操作和分桶操作1、分区操作2、分桶操作五、Hive函数六、文件格式和压缩格式一、Hive基本概念 Hive是什么? Hive:由 Facebook 开源用于解决海量结构化日志的…

监控易网络管理:网络流量分析

1、什么是网络流量分析2、网络流量分析的作用3、为什么要用网络流量分析功能,如何开启什么是网络流量分析简单的来说,网络流量分析就是捕捉网络中流动的数据包,并通过查看包内部数据以及进行相关的协议、流量、分析、统计等,协助发…