具有列表功能的有序字典实现 ListOrderedDict

本文最后更新于:2021年11月27日 下午

字典和列表都是python中常用的数据结构,各自有各自的优点,但有没有可以结合他们优点的数据结构呢,本文初步实现了具有列表功能的有序字典, 取名 ListOrderedDict。

背景

在python编程中,遇到了字典需要有序的情况,可以使用 collections 库中的 OrderedDict,在保持字典功能的同时使得其元素保持输入顺序;

但在此基础上又需要他拥有列表的性质:

  • 按序号索引
  • 切片提取数据
  • append 和 pop 操作

这就得自己开发了

ListOrderedDict 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
class ListOrderedDict(OrderedDict):
def __getitem__(self, key):
if is_integer(key):
key = list(self.keys())[key]
elif isinstance(key, slice):
slicedkeys = list(self.keys())[key]
lod_obj = type(self)()
for slicedkey in slicedkeys:
lod_obj[slicedkey] = self[slicedkey]
return lod_obj
return super().__getitem__(key)

def append(self, key, value):
if is_integer(key):
raise RuntimeError(f" integer key is not allowed in ListOrderedDict {key}.")
assert key not in self, f"cannot add existed key. {key}"
self[key] = value

def __setitem__(self, key, value):
'od.__setitem__(i, y) <==> od[i]=y'
# Setting a new item creates a new link at the end of the linked list,
# and the inherited dictionary is updated with the new key/value pair.
if is_integer(key):
raise RuntimeError(f" integer key is not allowed in ListOrderedDict {key}.")
else:
return super().__setitem__(key, value)

def __delitem__(self, key):
'od.__delitem__(y) <==> del od[y]'
# Deleting an existing item uses self.__map to find the link which gets
# removed by updating the links in the predecessor and successor nodes.
if is_integer(key):
key = list(self.keys())[key]

return super().__delitem__(key)

def move_to_end(self, key, last=True):
'''Move an existing element to the end (or beginning if last is false).

Raise KeyError if the element does not exist.
'''
if is_integer(key):
key = list(self.keys())[key]

return super().move_to_end(key, last)

def __repr__(self):
'od.__repr__() <==> repr(od)'
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, list(self.items()))

def pop(self, key=-1):
'''od.pop(k[,d]) -> v, remove specified key and return the corresponding
value. If key is not found, d is returned if given, otherwise KeyError
is raised.
'''
if is_integer(key):
if len(list(self.keys())) == 0:
print(f"pop a None from an empty ListOrderedDict.")
return None
key = list(self.keys())[key]
return super().pop(key)

def setdefault(self, key, default=None):
'''Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.
'''
if is_integer(key):
key = list(self.keys())[key]
return super().setdefault(key, default)

初步实现

  • 按整数下标提取元素
  • 切片
  • append
  • pop
  • 其他有序字典操作

使用

功能集成在了我的常用库 mtutils 中,可以pip直接安装

1
pip install mtutils

之后直接引用

1
from mtutils import ListOrderedDict

注意

  • 为了保持几种特性,牺牲了整数作为字典 key 的能力
  • 有问题欢迎随时交流