正确的方法来初始化一个 OrderedDect 使用它的构造函数,使它保留初始数据的顺序?

什么是正确的方法来初始化一个有序字典(OD) ,以便它保留初始数据的顺序?

from collections import OrderedDict


# Obviously wrong because regular dict loses order
d = OrderedDict({'b':2, 'a':1})


# An OD is represented by a list of tuples, so would this work?
d = OrderedDict([('b',2), ('a', 1)])


# What about using a list comprehension, will 'd' preserve the order of 'l'
l = ['b', 'a', 'c', 'aa']
d = OrderedDict([(i,i) for i in l])

问题:

  • OrderedDict是否会保留初始化时传递的元组列表、元组列表、元组列表或列表列表等的顺序(上面第2和第3个例子) ?

  • 如何去验证如果 OrderedDict实际上维护一个订单?因为 dict有一个不可预测的顺序,如果我的测试向量幸运地有一个与 dict 的不可预测顺序相同的初始顺序,该怎么办?例如,如果我写的是 d = OrderedDict({'a':1, 'b':2})而不是 d = OrderedDict({'b':2, 'a':1}),那么我可能会错误地得出顺序保持不变的结论。在这种情况下,我发现 dict是按字母顺序排列的,但这可能并不总是正确的。使用反例验证数据结构是否保持顺序的可靠方法是什么,除非反复尝试测试向量,直到其中一个中断?

另外,我把这个留给 参考文献: “ OrderedDect 构造函数和 update ()方法都接受关键字参数,但是它们的顺序丢失了,因为 Python 的函数调用语义使用常规的无序字典传入关键字参数。”

P.P.S: 希望将来 OrderedDect 也能保留 kwargs 的顺序(示例1) : http://bugs.python.org/issue16991

98594 次浏览
# An OD is represented by a list of tuples, so would this work?
d = OrderedDict([('b', 2), ('a', 1)])

是的,这样可以。根据定义,列表总是按其表示方式排序。这也适用于列表理解,生成的列表与提供数据的方式相同(例如,来自列表的源将是确定性的,来自 setdict的源不多)。

如何验证 OrderedDict实际上是否维护订单。既然 dict 有一个不可预测的顺序,那么如果我的测试向量幸运地具有与 dict 的不可预测顺序相同的初始顺序,该怎么办呢?.例如,如果我写的不是 d = OrderedDict({'b':2, 'a':1})而是 d = OrderedDict({'a':1, 'b':2}),我可能会错误地得出顺序保持不变的结论。在这种情况下,我发现 dict是按字母顺序排列的,但这可能并不总是正确的。也就是说,使用反例验证数据结构是否保持顺序的可靠方法是什么,或者不少于反复尝试测试向量,直到其中一个中断。

保留2-tuple 的源列表以供参考,并在进行单元测试时将其用作测试用例的测试数据。遍历它们并确保顺序得到维护。

OrderedDect 将保留它可以访问的任何顺序。将有序数据传递给它进行初始化的唯一方法是传递一个键-值对列表(或者更一般地说,一个可迭代的键-值对) ,如前两个示例所示。正如您链接到的文档所说,当您传入关键字参数或 dict 参数时,OrderedDect 不能访问任何顺序,因为在 OrderedDect 构造函数看到它之前,任何顺序都被移除了。

请注意,在上一个示例中使用列表内涵并不会改变任何事情。OrderedDict([(i,i) for i in l])OrderedDict([('b', 'b'), ('a', 'a'), ('c', 'c'), ('aa', 'aa')])之间没有区别。对列表内涵进行计算并创建列表,然后将其传入;。

使用生成器表达式也是可能的(而且效率更高一些) :

d = OrderedDict((i, i) for i in l)

显然,对于 l来说,这个小案例的好处可以忽略不计,但是如果 l对应于一个迭代器,或者从一个生成器产生结果,例如,用于解析和迭代一个大文件,那么差异可能是非常显著的(例如,避免将整个内容加载到内存中)。例如:

def mygen(filepath):
with open(filepath, 'r') as f:
for line in f:
yield [int(field) for field line.split()]


d = OrderedDict((i, sum(numbers)) for i, numbers in enumerate(mygen(filepath)))