【问题标题】:how to assign list of values to a key using OrderedDict in python如何在python中使用OrderedDict将值列表分配给键
【发布时间】:2012-11-07 07:21:42
【问题描述】:

您好想要一个有序字典,其中的键具有值列表。

从下面的代码中,我可以得到一个包含键列表的字典,但插入的顺序丢失了。

from collections import defaultdict

keys=['blk','pri','ani']
vals1=['blocking','primary','anim']
vals2=['S1','S2','S3']
dic = defaultdict(list)

i=0

for key in keys:
    dic[key].append(vals1[i])
    dic[key].append(vals2[i])

    i += 1

print dic

我得到以下结果

defaultdict(<type 'list'>, {'pri': ['primary', 'S2'], 'ani': ['anim', 'S3'], 'blk': ['blocking', 'S1']})

这里我丢失了插入顺序。

我知道 Python 中的 defaultdict 对象是按定义无序的

如果您需要插入值的顺序,我知道我们需要使用 OrderedDict(它在 Python 2.7 和 3.x 中可用)

所以修改了我的代码如下

从下面的代码我可以得到我需要的东西。

from collections import defaultdict,OrderedDict

keys=['blk','pri','ani']
vals1=['blocking','primary','anim']
vals2=['S1','S2','S3']
dic = OrderedDict(defaultdict(list))

i=0

for key in keys:
    dic[key].append(vals1[i])
    dic[key].append(vals2[i])

    i += 1

print dic

现在我得到以下错误

Traceback (most recent call last):
  File "Dict.py", line 18, in <module>
    dic[key].append(vals1[i])
KeyError: 'blk' 

谁能告诉我如何得到我正在尝试的东西。

【问题讨论】:

  • 附带说明,您几乎从不想维护这样的显式循环计数器。只是for i, key in enumerate(keys):。 (实际上,在这种情况下,您甚至不需要循环计数器。只需 for key, val1, val2 in zip(keys, vals1, vals2):。)
  • 另外,您真的需要保留插入顺序吗?通常,新手会要求这样做,但解决实际问题的正确方法实际上并不需要它。事实上,这种情况非常普遍,以至于在标准库中添加OrderedDict 存在严重的阻力,因为担心它会鼓励滥用。 (IIRC,它在 2.4、2.5 和 2.6 中被拒绝,最终在 3.0 和 2.7 中被接受。)
  • @abarnert,是的,我真的需要它。我为它创建了自己的课程,它解决了我的问题。

标签: python dictionary


【解决方案1】:

OrderedDict 包裹在defaultdict(list) 周围的问题在于它是这样评估的:

  1. 创建defaultdict 的空实例。
  2. 创建一个OrderedDict 的实例,然后使用defaultdict 的内容(当前为空)对其进行初始化,然后丢弃旧的defaultdict,因为不再引用它。

这并没有像你想要的那样结合他们的行为。

我见过的标准习语是dict.setdefault 方法。

from collections import OrderedDict

keys=['blk','pri','ani']
vals1=['blocking','primary','anim']
vals2=['S1','S2','S3']
dic = OrderedDict()

i=0

for key in keys:
    dic.setdefault(key, []).append(vals1[i])
    dic.setdefault(key, []).append(vals2[i])

    i += 1

print dic

与 defaultdict 一样,这会在您第一次访问它时创建一个值,尽管我认为它的效率有点低。

不过我会使用这种方法:

from collections import OrderedDict
dic = OrderedDict(zip(keys, zip(vals1, vals2)))
print dic

【讨论】:

  • 刚刚得到相同的简短解决方案))))
  • 效率较低。实际上,我曾经通过以适当的顺序对它们进行子类化来创建OrderedDefaultDict——但这似乎是一个非常脆弱的解决方案,我不会在这里尝试重现它。
  • @mgilson,您能解释一下效率低下的原因吗?只是因为每次无条件分配一个空列表,对吧?
  • 另请注意,您使用zip 的解决方案并不完全等效。 zip 会给 OP tuples 而不是列表,所以 OP 以后不能.append。你可能需要zip(keys,map(list,zip(vals1,vals2)))
  • @JameySharp -- 正确。即使您不必这样做,您也可以使用setdefault 创建一个列表。列表创建虽然经过高度优化,所以在这里可能没什么大不了的,除非你要这样做很多次。
【解决方案2】:

如果你真的想要“有序”“默认”行为,我想我会创建一个自定义字典类来为我处理所有事情:

from collections import OrderedDict

class DefaultListOrderedDict(OrderedDict):
    def __missing__(self,k):
        self[k] = []
        return self[k]

keys=['blk','pri','ani']
vals1=['blocking','primary','anim']
vals2=['S1','S2','S3']
dic = DefaultListOrderedDict()
for i,key in enumerate(keys):
    dic[key].append(vals1[i])
    dic[key].append(vals2[i])

print dic

与其他解决方案相比,这将更像defaultdict,但它会保留它的顺序,而且它真的不是很多代码:)。最后,您甚至可以覆盖__init__ 以允许用户传递他们想要的任何“工厂”(而不是硬编码list)。我将把它作为练习留给感兴趣的读者。 Python 太酷了。

【讨论】:

  • 很好,不知道__missing__这个特殊方法。 special method names 的列表中没有提到它,而只是在 dict built-in type 的文档中简要提及。一个大 +1!
  • 由于 python 2.6 没有 OrderedDict,我为它创建了一个类并使用了 DefaultListOrderedDict。它解决了我的问题。谢谢帮助
  • @PBLNarasimhaRao -- 仅供参考,有一个用于 python 2.4+ 的有序 dict 的 activeState 配方 -- code.activestate.com/recipes/576693-ordered-dictionary-for-py24
  • @mgilson -- 我只使用了那个类。
【解决方案3】:

试试这个:

from collections import OrderedDict

keys=['blk','pri','ani']
vals1=['blocking','primary','anim']
vals2=['S1','S2','S3']
print OrderedDict(zip(keys, zip(vals1, vals2)))

【讨论】:

    猜你喜欢
    • 2021-05-28
    • 2021-12-27
    • 2020-12-28
    • 1970-01-01
    • 2019-03-12
    • 2017-07-05
    • 2017-07-17
    • 1970-01-01
    • 2019-03-14
    相关资源
    最近更新 更多