【问题标题】:copy part of one dict to a new dict based on a list of keys根据键列表将一个字典的一部分复制到新字典
【发布时间】:2014-10-22 17:14:50
【问题描述】:

示例:

d = {
    "test": 1,
    "sample": 2,
    "example": 3,
    "product": 4,
    "software": 5,
    "demo": 6,
}

filter_keys = ["test","sample","example","demo"]

我想创建一个新的 dict,它只包含第一个 dict 中其键出现在列表中的项目。换句话说,我想要:

d2 = {
    "test": 1,
    "sample": 2,
    "example": 3,
    "demo": 6,
}

我可以用循环来做到这一点:

d2 = {}
for k in d.keys():
    if (k in filter_keys): 
        d2[k] = d[k]

但这似乎非常“非 Pythonic”。我还猜测,如果你有一个巨大的字典,比如 5,000 个左右的项目,与更直接的方式相比,不断向新字典添加新项目会很慢。

此外,您还希望能够处理错误。如果列表包含不是字典中的键的内容,则应将其忽略。或者它可能被添加到新的字典中,但值为 None。

有没有更好的方法来做到这一点?

【问题讨论】:

  • 您已经问了很多问题,但没有接受这些问题的答案。你应该接受答案。

标签: python dictionary


【解决方案1】:

一个直接的方法是使用“字典理解”:

filtered_dict = {key: value for key, value in d.items() if key in filter_keys}

请注意,如果条件出现在推导式的末尾,它会过滤循环语句的执行。根据字典中的键数是否大于您要过滤的键数,此修订可能更有效:

filtered_dict = {key: d[key] for key in filter_keysif key in d}

检查字典中的成员资格 (key in d) 比检查筛选键列表中的成员资格 (key in filter_keys) 快得多。但最终哪个更快取决于过滤器键列表的大小(在较小程度上,还取决于字典的大小)。

在没有字典理解的情况下,一种相对 Python 的方法是使用 dict 构造函数:

filtered_dict = dict([(key, value) for key, value in d.items() if key in filter_keys])

请注意,这本质上等同于字典推导,但如果您不熟悉字典推导语法,可能会更清楚。

【讨论】:

  • 无需构建一个列表来传递给 dict 构造函数——生成器表达式就可以了。
  • 对字典的理解太棒了。我一直在使用列表推导,但从不知道你可以用 dict 做同样的事情。
  • @fdmillion -- 是的,它们与集合理解一起被添加到 python2.7 中,例如:{x*x for x in something}
  • 是的,该列表不是必需的。您可以编写dict((key, value) for key, value in d.items() if key in l),它将生成器传递给dict 构造函数。在这种情况下,它们的速度可能大致相同。
【解决方案2】:

根据您问题的最后一部分:

或者它可能被添加到新的字典中,但值为 None。

l = ["test","sample","example","demo","badkey"]
d = {
    "test": 1,
    "sample": 2,
    "example": 3,
    "product": 4,
    "software": 5,
    "demo": 6,
}


print {k: d.get(k) for k in l}
{'test': 1, 'sample': 2, 'badkey': None, 'example': 3, 'demo': 6}

您可以将默认返回值传递给dict.get,默认情况下为None,但您可以将其设置为d.get(k,"No_match") 等...或任何您想要的值。

【讨论】:

    【解决方案3】:

    为了获得最佳性能,您应该遍历列表中的键并检查它们是否在字典中,而不是相反:

    d2 = {}
    for k in list_of_keys:
        if k in d:
           d2[k] = d[k]
    

    这里的好处是 dict 上的 dict.__contains__ (in) 是 O(1),而列表是 O(N)。对于大型列表,这是一个巨大的好处(O(N) 算法与 O(N^2))。

    我们可以用等效的 dict-comprehension 来表达上面的循环,更简洁一点:

    d2 = {k: d[k] for k in list_of_keys if k in d} 
    

    这可能会比循环稍微快一点,但可能还不够担心。也就是说,大多数 Python 程序员更喜欢这个版本,因为它更简洁且非常常见。

    【讨论】:

    • @EML,想想逻辑,为什么要遍历整个 dict 而不仅仅是四个列表项?
    • 对不起,我删除了我的评论 - 我打算编辑它。这是否更有效取决于我们打算过滤的键是否实际上是字典中键的子集。过滤器列表可能大于字典中实际的键数。当然,查看字典而不是列表可以节省大量费用,因此我编辑了我的评论以反映这一点。
    【解决方案4】:

    字典理解是一种方法:

    new_d = {k: v for k, v in d.items() if k in l}
    

    演示:

    >>> d = {
    ...     "test": 1,
    ...     "sample": 2,
    ...     "example": 3,
    ...     "product": 4,
    ...     "software": 5,
    ...     "demo": 6,
    ... }
    >>>
    >>> l = ["test","sample","example","demo"]
    >>> new_d = {k: v for k, v in d.items() if k in l}
    >>> new_d
    {'sample': 2, 'demo': 6, 'test': 1, 'example': 3}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      • 2017-11-06
      • 2022-11-15
      • 2017-11-27
      • 2022-11-30
      • 2022-06-23
      相关资源
      最近更新 更多