赞
踩
在许多场景中,有时需要通过多种信息来获取某个特定的值,而各种编程语言(包括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)所对应的值。
有两种方式可以实现上面提到的“多键字典”。
key_1,key_2,...key_n
(即所有键之间用逗号分隔),然后用已有的字典dict
映射即可。注意,键之间一定要有分隔符
,如果直接连接起来的话,有可能会造成哈希冲突导致两个不同的多键对被映射到同一处。例如:(aa,b)
和(a,ab)
中的键如果直接连接都会形成aab
的字符串,导致哈希冲突。这种方式实现起来比较简单。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_key_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_key_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)->List[Tuple[Tuple,Any]]: """Get set of all "(keys,val)" in multi_key_dict. """ mutli_keys_dict_items = [] for key in self.__keys: print(key) val = self.get_value(key) print(val) mutli_keys_dict_items.append((key,val)) return mutli_keys_dict_items def __contains__(self,keys:tuple)->bool: """Check whether the given multi_key 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()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。