【问题标题】:"Flattening" a list of dictionaries“扁平化”字典列表
【发布时间】:2013-03-26 21:24:07
【问题描述】:

所以我的目标是:

fruitColourMapping = [{'apple': 'red'}, {'banana': 'yellow'}]

finalMap = {'apple': 'red', 'banana': 'yellow'}

我得到的一个方法是:

 from itertools import chain
 fruits = list(chain.from_iterable([d.keys() for d in fruitColourMapping]))
 colour = list(chain.from_iterable([d.values() for d in fruitColourMapping]))
 return dict(zip(fruits, colour))

还有更好的pythonic方式吗?

【问题讨论】:

  • 仅供参考,你真的不想这样做。字典本质上是无序的,因此迭代字典两次(就像构建fruitcolor 列表一样)以正确的顺序生成两组值只是运气问题。
  • @sr2222 不正确。文档explicitly states 指出,如果您在不同时改变字典的情况下迭代键和值,则可以保证顺序一致。
  • @DanielRoseman 这仍然不是一个好习惯。如果这成为一个问题,它将不是线程安全的,并且仅仅因为某些东西实现了与字典相同的接口并不意味着它在这些细节上的行为与字典完全一样。这是一种可以正常工作直到不能正常工作的东西,然后你会变得难以追踪错误。这很容易避免,所以您不妨这样做。

标签: python dictionary


【解决方案1】:

为什么要复制?

在 Python 3 中,您可以使用新的ChainMap

ChainMap 将多个 dicts(或其他映射)组合在一起以创建一个可更新的视图。
底层映射存储在列表中。该列表是公开的,并且 可以使用 maps 属性访问或更新。没有 其他状态。查找连续搜索底层映射 直到找到密钥。相反,写入、更新和删除 只对第一个映射进行操作。

您只需要这样做(更改名称以遵守Python naming conventions):

from collections import ChainMap
fruit_colour_mapping = [{'apple': 'red'}, {'banana': 'yellow'}]
final_map = ChainMap(*fruit_colour_mapping)

然后你就可以使用所有正常的映射操作了:

# print key value pairs:
for element in final_map.items():
    print(element)

# change a value:
final_map['banana'] = 'green'    # supermarkets these days....

# access by key:
print(final_map['banana'])

【讨论】:

  • +1 我认为这是 python 3 中更酷的 dict 添加之一。第一次在新的 Python Cookbook 中看到它。
  • ChainMap 的搜索操作比 Python 字典慢很多。您应该将 final_map 转换为 Python 字典。
【解决方案2】:
finalMap = {}
for d in fruitColourMapping:
    finalMap.update(d)

【讨论】:

  • 只是好奇:如果 'd's 之一是 {'apple': 'red', 'orange': 'orange'},它应该工作吗?
  • 此代码将简单地将所有字典条目添加到finalMap,因此它将添加appleorange 键。
  • 在超越简单示例时,请确保所有键都是全局唯一的,因为update(或任何以单个 dict 结尾的方法)将对键进行重复数据删除。如果您需要所有重复项(例如,当所有 dicts 具有相同的键时),请在连接之前将 dicts 转换为 pandas DataFrames。
【解决方案3】:
{k: v for d in fruitColourMapping for k, v in d.items()}

【讨论】:

    【解决方案4】:

    与其解构重构,不如复制更新:

    final_map = {}
    for fruit_color_definition in fruit_color_mapping:
        final_map.update(fruit_color_definition)
    

    【讨论】:

      【解决方案5】:
      dict(d.items()[0] for d in fruitColourMapping)
      

      【讨论】:

        【解决方案6】:

        方法

        使用reduce 将每个字典应用到一个空的初始化器。由于dict.update 总是返回None,因此使用d.update(src) or dreduce 提供所需的返回值。

        代码

        final_dict = reduce(lambda d, src: d.update(src) or d, dicts, {})
        

        测试

        >>> dicts = [{'a': 1, 'b': 2}, {'b': 3, 'c': 4}, {'a': 6}]
        >>> final_dict = reduce(lambda d, src: d.update(src) or d, dicts, {})
        >>> final_dict
        {'a': 6, 'c': 4, 'b': 3}
        

        【讨论】:

        • 为了不那么老套,您可以考虑使用新的 dict 合并语法和 OR 运算符的重载:final_dict = reduce(lambda x, y: x | y, dicts, {})
        • @NeiNeto 您的评论不合时宜。当我在 2013 年写这篇文章时,最新的 python 是 3.3.0。你建议我应该写的功能几年后就不存在了。
        • 确实如此。非常糟糕的时刻。幸运的是,由于我的评论不合时宜,我所指的“你”是读者而不是你,休。顺便说一句,那一天的好话,感觉就像是直接来自 vsauce 的东西。不过,您会考虑编辑您的答案吗?
        【解决方案7】:

        给定

        d1, d2 = [{'apple': 'red'}, {'banana': 'yellow'}]
        

        代码

        在 Python 3.5 中,引入了字典解包(参见 PEP 448):

        {**d1, **d2}
        # {'apple': 'red', 'banana': 'yellow'}
        

        在 Python 3.9 中,引入了 merge operator

        d1 | d2
        # {'apple': 'red', 'banana': 'yellow'}
        

        【讨论】:

          【解决方案8】:

          我想出了一个有趣的单班轮。

          >>> a = [{"wow": 1}, {"ok": 2}, {"yeah": 3}, {"ok": [1,2,3], "yeah": True}]
          >>> a = dict(sum(map(list, map(dict.items, a)), []))
          >>> a
          {'wow': 1, 'ok': [1, 2, 3], 'yeah': True}
          

          【讨论】:

            【解决方案9】:

            你也可以试试:

            finalMap = dict(item for mapping in fruitColourMapping for item in mapping.items())

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2022-10-24
              • 1970-01-01
              • 2019-02-04
              • 2022-01-17
              • 1970-01-01
              • 2016-01-14
              • 1970-01-01
              • 2021-12-08
              相关资源
              最近更新 更多