使用其构造函数初始化OrderedDict的正确方法,使其保留初始数据的顺序?

时间:2014-08-25 06:25:39

标签: python sorting dictionary ordereddictionary

初始化有序字典(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({'b':2, 'a':1})代替d = OrderedDict({'a':1, 'b':2}),我可能会错误地断定订单被保留。在这种情况下,我发现dict按字母顺序排序,但可能并非总是如此。什么是使用反例验证数据结构是否保留顺序的可靠方法,没有重复尝试测试向量直到中断?

P.S。我将这里留给reference:" OrderedDict构造函数和update()方法都接受关键字参数,但它们的顺序丢失,因为Python的函数调用语义传入关键字参数使用a常规无序字典"

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

3 个答案:

答案 0 :(得分:78)

OrderedDict将保留其有权访问的任何订单。将有序数据传递给它以进行初始化的唯一方法是传递一个列表(或更常见的是可迭代的)键值对,如前两个示例所示。如您链接的文档所示,当您传递关键字参数或dict参数时,OrderedDict无权访问任何订单,因为在OrderedDict构造函数看到它之前,任何订单都被删除。

请注意,在上一个示例中使用列表推导并不会改变任何内容。 OrderedDict([(i,i) for i in l])OrderedDict([('b', 'b'), ('a', 'a'), ('c', 'c'), ('aa', 'aa')])之间没有区别。评估列表推导并创建列表并将其传入; OrderedDict对它的创建方式一无所知。

答案 1 :(得分:64)

# 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元组的源列表以供参考,并在进行单元测试时将其用作测试用例的测试数据。迭代它们并确保维持订单。

答案 2 :(得分:0)

也可以(而且效率更高)使用生成器表达式:

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)))