python中有序字典的有序字典
我需要一个存储字典的字典数据结构,如下所示:python中有序字典的有序字典,python,dictionary,Python,Dictionary,我需要一个存储字典的字典数据结构,如下所示: custom = {1: {'a': np.zeros(10), 'b': np.zeros(100)}, 2: {'c': np.zeros(20), 'd': np.zeros(200)}} 但问题是我在代码中多次迭代这个数据结构。每次迭代时,我都需要遵守迭代顺序,因为这个复杂数据结构中的所有元素都映射到一个1D数组(如果愿意,可以序列化),因此顺序很重要。为此,我考虑过编写一个有序的dict,但我不确定这是正确的解决方案
custom = {1: {'a': np.zeros(10), 'b': np.zeros(100)},
2: {'c': np.zeros(20), 'd': np.zeros(200)}}
但问题是我在代码中多次迭代这个数据结构。每次迭代时,我都需要遵守迭代顺序,因为这个复杂数据结构中的所有元素都映射到一个1D数组(如果愿意,可以序列化),因此顺序很重要。为此,我考虑过编写一个有序的dict
,但我不确定这是正确的解决方案,因为我可能选择了错误的数据结构。对于我的情况,什么是最合适的解决方案
更新
这就是我到目前为止的想法:
class Test(list):
def __init__(self, *args, **kwargs):
super(Test, self).__init__(*args, **kwargs)
for k,v in args[0].items():
self[k] = OrderedDict(v)
self.d = -1
self.iterator = iter(self[-1].keys())
self.etype = next(self.iterator)
self.idx = 0
def __iter__(self):
return self
def __next__(self):
try:
self.idx += 1
return self[self.d][self.etype][self.idx-1]
except IndexError:
self.etype = next(self.iterator)
self.idx = 0
return self[self.d][self.etype][self.idx-1]
def __call__(self, d):
self.d = -1 - d
self.iterator = iter(self[self.d].keys())
self.etype = next(self.iterator)
self.idx = 0
return self
def main(argv=()):
tst = Test(elements)
for el in tst:
print(el)
# loop over a lower dimension
for el in tst(-2):
print(el)
print(tst)
return 0
if __name__ == "__main__":
sys.exit(main())
在这个有序结构中,我可以迭代任意次数,并且我实现了
\uuuuu call\uuuu
,因此我可以在较低的维度上迭代。我不喜欢这样的事实,如果列表中没有较低的维度,它不会给我任何错误。我还感到,每次调用返回self[self.d][self.etype][self.idx-1]
时,效率都低于字典上最初的迭代。这是真的吗?我该如何改进这一点呢?你能用一系列字典吗
custom = [{'a': np.zeros(10), 'b': np.zeros(100)},
{'c': np.zeros(20), 'd': np.zeros(200)}]
如果外部字典是您唯一需要的顺序正确的字典,那么这可能会起作用。您仍然可以使用custom[0]
或custom[1]
访问内部词典(请注意,索引现在从0
开始)
如果未使用所有索引,则可以执行以下操作:
custom = [None] * maxLength # maximum dict size you expect
custom[1] = {'a': np.zeros(10), 'b': np.zeros(100)}
custom[2] = {'c': np.zeros(20), 'd': np.zeros(200)}
custom[1]['b']
当您首先对键进行排序时,可以在迭代时修复键的顺序:
for key in sorted(custom.keys()):
print(key, custom[key])
如果要减少sorted()
-调用,可能需要将键存储在一个额外的列表中,该列表将用作迭代顺序:
ordered_keys = sorted(custom.keys())
for key in ordered_keys:
print(key, custom[key])
您应该准备好根据需要在数据结构上进行尽可能多的迭代。我认为使用
orderedict
s是最好的方法。它们是内置的,速度相对较快:
custom = OrderedDict([(1, OrderedDict([('a', np.zeros(10)),
('b', np.zeros(100))])),
(2, OrderedDict([('c', np.zeros(20)),
('d', np.zeros(200))]))])
若您想使迭代数据结构的内容变得容易,您可以始终提供一个实用函数:
def iter_over_contents(data_structure):
for delem in data_structure.values():
for v in delem.values():
for row in v:
yield row
请注意,在Python 3.3+中,允许从生成,可以消除
循环的最后一个:
def iter_over_contents(data_structure):
for delem in data_structure.values():
for v in delem.values():
yield from v
有了其中一个,你就可以写下如下内容:
for elem in iter_over_contents(custom):
print(elem)
隐藏复杂性
虽然您可以定义自己的类来封装此数据结构,并使用iter\u over\u contents()
generator函数作为其\uuu iter\uu()
方法,但这种方法可能会更慢,不允许表达式使用以下两种级别的索引:
custom = [None] * maxLength # maximum dict size you expect
custom[1] = {'a': np.zeros(10), 'b': np.zeros(100)}
custom[2] = {'c': np.zeros(20), 'd': np.zeros(200)}
custom[1]['b']
使用嵌套字典(或我的另一个答案中所示的
OrderedDefaultdicts)可以实现这一点。这里有另一种选择,它使用OrderedDefaultdict来定义所需的树状数据结构。我在重复我的另一个定义
要使用它,您必须确保这些条目是按照您稍后要访问它们的顺序定义的
class OrderedDefaultdict(OrderedDict):
def __init__(self, *args, **kwargs):
if not args:
self.default_factory = None
else:
if not (args[0] is None or callable(args[0])):
raise TypeError('first argument must be callable or None')
self.default_factory = args[0]
args = args[1:]
super(OrderedDefaultdict, self).__init__(*args, **kwargs)
def __missing__ (self, key):
if self.default_factory is None:
raise KeyError(key)
self[key] = default = self.default_factory()
return default
def __reduce__(self): # optional, for pickle support
args = (self.default_factory,) if self.default_factory else ()
return self.__class__, args, None, None, self.iteritems()
Tree = lambda: OrderedDefaultdict(Tree)
custom = Tree()
custom[1]['a'] = np.zeros(10)
custom[1]['b'] = np.zeros(100)
custom[2]['c'] = np.zeros(20)
custom[2]['d'] = np.zeros(200)
我不确定我是否理解你的后续问题。如果数据结构仅限于两个级别,则可以使用嵌套的for
循环,按照定义的顺序迭代其元素。例如:
for key1, subtree in custom.items():
for key2, elem in subtree.items():
print('custom[{!r}][{!r}]: {}'.format(key1, key2, elem))
(在Python 2中,您可能想使用
iteritems()
而不是items()
)我不能使用它,因为1可能存在,也可能不存在,0和2也是如此。啊,好的,所以您实际上需要外部dict
中的键-没关系,抱歉误解了@aaragon我编辑了答案,以保留作为外部dict
键的索引,并将所有不可用元素设置为None
。您的解决方案仍然没有排序,例如,通过custom[1]
循环可以获得a
的元素,然后b
,在不同的迭代中,元素b
,然后a
。这可以通过使用OrderedDict
来解决,但是问题仍然存在:有没有更好的方法来处理这个问题?我在这个数据结构上迭代了很多次。这个结构在整个应用程序中迭代了很多次,我想做的是为k提供一个更为用户友好的方法来键入,custom.items()中的v:对于枚举(v)中的i,r:#等
这似乎是一个完全不同的问题。的确,请看一看,但我必须仔细考虑这一点,因此我从选择正确的数据结构开始。感谢您的解决方案。如果您必须提供一个更友好的用户界面,以便按顺序遍历字典中的元素,那么有可能吗?假设我想在custom:中为el执行,然后以有序的方式逐个遍历每个元素,你会怎么做?我的意思是,只使用一个循环,就可以按顺序遍历整个数据结构。我试图通过重写\uu iter\uuu
和\uu next\uuu
方法来实现这一点,但我失败得很惨。我还想问您是否可以解释一下您编写的代码,因为这对我来说是非常高级的Python。对于字典,\uuuuu iter\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,然而,基于字典的递归树结构可以支持多种形式的迭代——例如,宽度优先和深度优先遍历。此外,字典还有一个items()
方法,它返回它所包含的所有(键、值)
对的副本。由于这些差异,当您只说您希望按顺序遍历元素时,不清楚您试图实现什么。在这个上下文中,你认为什么是“元素”?我的答案中的代码是前