【问题标题】:Most efficient way to add new keys or append to old keys in a dictionary during iteration in Python?在 Python 中的迭代期间添加新键或附加到字典中旧键的最有效方法?
【发布时间】:2010-09-28 15:54:03
【问题描述】:

以下是从不同来源编译字典中的数据时的常见情况:

假设你有一本存储事物列表的字典,例如我喜欢的事物:

likes = {
    'colors': ['blue','red','purple'],
    'foods': ['apples', 'oranges']
}

还有一个包含一些相关值的字典:

favorites = {
    'colors':'yellow',
    'desserts':'ice cream'
}

然后,您想要遍历“收藏夹”对象,或者将该对象中的项目附加到具有“喜欢”字典中适当键的列表中,或者向其添加一个新键,其值为包含“收藏夹”中的值。

有几种方法可以做到这一点:

for key in favorites:
    if key in likes:
        likes[key].append(favorites[key])
    else:
        likes[key] = list(favorites[key])

或

for key in favorites:
    try:
        likes[key].append(favorites[key])
    except KeyError:
        likes[key] = list(favorites[key])

还有更多...

我通常使用第一种语法,因为它感觉更像 Python,但如果有其他更好的方法,我很想知道它们是什么。谢谢!

【问题讨论】:

    标签: python iteration


    【解决方案1】:

    使用collections.defaultdict,其中默认值为新的list 实例。

    >>> import collections
    >>> mydict = collections.defaultdict(list)
    

    以这种方式调用.append(...) 将始终成功,因为如果键不存在,append 将在一个新的空列表上调用。

    您可以使用先前生成的列表来实例化defaultdict,以防您从其他来源获得字典likes,如下所示:

    >>> mydict = collections.defaultdict(list, likes)
    

    请注意,使用list 作为defaultdict 的default_factory 属性也在documentation 中作为示例进行了讨论。

    【讨论】:

    • 2.5 及更高版本,或者您必须定义自己的 defaultdict 类。
    【解决方案2】:

    使用 collections.defaultdict:

    import collections
    
    likes = collections.defaultdict(list)
    
    for key, value in favorites.items():
        likes[key].append(value)
    

    defaultdict 采用单个参数,即按需为未知键创建值的工厂。 list 就是这样一个函数,它会创建空列表。

    遍历 .items() 将使您免于使用键来获取值。

    【讨论】:

    • 使用 .items() 的好技巧。这是我喜欢 Python 的原因之一。总会有更好、更快、更智能的方法。
    【解决方案3】:

    除了 defaultdict,常规 dict 提供了一种可能性(可能看起来有点奇怪):dict.setdefault(k[, d]):

    for key, val in favorites.iteritems():
        likes.setdefault(key, []).append(val)
    

    感谢您的 +20 代表 - 我在 30 秒内从 1989 年到 2009 年。让我们记住,欧洲的柏林墙倒塌已经 20 年了。

    【讨论】:

    • 啊,很好。 defaultdict 在这里似乎是“正确”的解决方案,但这是一个很酷的选择。
    • 请注意,docs.python.org/3.1/library/… 的第一个示例明确指出使用 defaultdict 比使用 setdefault 方法更快。
    • 另一个警告是值必须是可变的,这不起作用:likes.setdefault(key, 0) += 1
    • 对 setdefault 的另一个考虑:它会评估它的两个参数,因此即使键存在,您仍然会创建和处理空列表。
    • setdefault 是在 defaultdict 之前执行此操作的方法。现在感觉有点尴尬
    【解决方案4】:
    >>> from collections import defaultdict
    >>> d = defaultdict(list, likes)
    >>> d
    defaultdict(<class 'list'>, {'colors': ['blue', 'red', 'purple'], 'foods': ['apples', 'oranges']})
    >>> for i, j in favorites.items():
        d[i].append(j)
    
    >>> d
    defaultdict(<class 'list'>, {'desserts': ['ice cream'], 'colors': ['blue', 'red', 'purple', 'yellow'], 'foods': ['apples', 'oranges']})
    

    【讨论】:

      【解决方案5】:

      所有答案都是defaultdict,但我不确定这是最好的解决方法。将 defaultdict 分配给需要 dict 的代码可能很糟糕。 (请参阅:How do I make a defaultdict safe for unexpecting clients?)我个人对此事感到困惑。 (我实际上发现这个问题是在寻找“哪个更好,dict.get() 或 defaultdict”的答案)另一个线程中的某个人说,如果你不想要这种行为,你不想要 defaultdict时间,这可能是真的。也许为了方便而使用 defaultdict 是错误的方法。我认为这里有两个需求被混为一谈:

      “我想要一个默认值为空列表的字典。” defaultdict(list) 是正确的解决方案。

      和

      “如果它存在,我想附加到这个键的列表,如果它不存在,我想创建一个列表。” my_dict.get('foo', []) 和 append() 是答案。

      你们觉得呢?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-13
        • 1970-01-01
        • 2016-04-07
        • 2010-11-21
        • 1970-01-01
        • 1970-01-01
        • 2017-05-28
        相关资源
        最近更新 更多