【问题标题】:Merge two lists of dicts of different lengths using a single key in Python在 Python 中使用单个键合并两个不同长度的字典列表
【发布时间】:2017-12-29 20:13:23
【问题描述】:

当两个列表长度不同时(使用 Python 3.6),我想在一个键上合并两个字典列表。例如,如果我们有一个名为 l1 的字典列表:

l1 = [{'pcd_sector': 'ABDC', 'coverage_2014': '100'},
       {'pcd_sector': 'DEFG', 'coverage_2014': '0'}]

还有另一个名为l2的字典列表:

l2 = [{'pcd_sector': 'ABDC', 'asset': '3G', 'asset_id': '2gs'},
      {'pcd_sector': 'ABDC', 'asset': '4G', 'asset_id': '7jd'},
      {'pcd_sector': 'DEFG', 'asset': '3G', 'asset_id': '3je'},
      {'pcd_sector': 'DEFG', 'asset': '4G', 'asset_id': '8js'},
      {'pcd_sector': 'CDEF', 'asset': '3G', 'asset_id': '4jd'}]

如何使用pcd_sector 合并它们以获得这个(?):

result = [{'pcd_sector': 'ABDC', 'asset': '3G', 'asset_id': '2gs', 'coverage_2014': '100'},
          {'pcd_sector': 'ABDC', 'asset': '4G', 'asset_id': '7jd', 'coverage_2014': '100'},
          {'pcd_sector': 'DEFG', 'asset': '3G', 'asset_id': '3je', 'coverage_2014': '0'},
          {'pcd_sector': 'DEFG', 'asset': '4G', 'asset_id': '8js', 'coverage_2014': '0'},
          {'pcd_sector': 'CDEF', 'asset': '3G', 'asset_id': '4jd'}]

到目前为止我已经尝试过什么

我已使用以下代码合并两个列表,但不幸的是,我最终得到了一个简短的版本,而不是所需的完整数据结构。

import pprint
grouped = {}
for d in l1 + l2:
    grouped.setdefault(d['pcd_sector'], {'asset':0, 'asset_id':0, 'coverage_2014':0}).update(d)
result = [d for d in grouped.values()]
pprint.pprint(result)

所以当我运行代码时,我会得到这个简短的输出:

result = [{'pcd_sector': 'ABDC', 'asset': '3G', 'asset_id': '2gs', 'coverage_2014': '100'},
         {'pcd_sector': 'DEFG', 'asset': '4G', 'asset_id': '8js', 'coverage_2014': '0'},
         {'pcd_sector': 'CDEF', 'asset': '3G', 'asset_id': '4jd'}]

【问题讨论】:

    标签: python list dictionary merge


    【解决方案1】:

    问题

    您的方法中的问题是您的数据被放入grouped dict 中,'pcd_sector' 作为键,但您的l2 有多个具有相同'pcd_sector' 的dicts。您可以使用 'pcd_sector', 'asset' 的元组作为 l2 的键,但它不再适用于 l1。所以你需要分两步进行处理,而不是直接在l1 + l2上迭代。

    理论

    如果pcd_sector 键在l1 中是唯一的,您可以创建一个大字典而不是小字典列表:

    >>> d1 = {d['pcd_sector']:d for d in l1}
    >>> d1
    {'ABDC': {'pcd_sector': 'ABDC', 'coverage_2014': '100'}, 'DEFG': {'pcd_sector': 'DEFG', 'coverage_2014': '0'}}
    

    然后,您只需合并具有相同pcd_sector 键的字典:

    >>> [dict(d, **d1.get(d['pcd_sector'], {})) for d in l2]
    [{'asset_id': '2gs', 'coverage_2014': '100', 'pcd_sector': 'ABDC', 'asset': '3G'}, {'asset_id': '7jd', 'coverage_2014': '100', 'pcd_sector': 'ABDC', 'asset': '4G'}, {'asset_id': '3je', 'coverage_2014': '0', 'pcd_sector': 'DEFG', 'asset': '3G'}, {'asset_id': '8js', 'coverage_2014': '0', 'pcd_sector': 'DEFG', 'asset': '4G'}, {'asset_id': '4jd', 'pcd_sector': 'CDEF', 'asset': '3G'}]
    

    完整代码

    综合起来,代码变成:

    l1 = [{'pcd_sector': 'ABDC', 'coverage_2014': '100'},
           {'pcd_sector': 'DEFG', 'coverage_2014': '0'}]
    
    l2 = [{'pcd_sector': 'ABDC', 'asset': '3G', 'asset_id': '2gs'},
          {'pcd_sector': 'ABDC', 'asset': '4G', 'asset_id': '7jd'},
          {'pcd_sector': 'DEFG', 'asset': '3G', 'asset_id': '3je'},
          {'pcd_sector': 'DEFG', 'asset': '4G', 'asset_id': '8js'},
          {'pcd_sector': 'CDEF', 'asset': '3G', 'asset_id': '4jd'}]
    
    d1 = {d['pcd_sector']:d for d in l1}
    result = [dict(d, **d1.get(d['pcd_sector'], {})) for d in l2]
    
    import pprint
    pprint.pprint(result)
    #   [{'asset': '3G',
    #     'asset_id': '2gs',
    #     'coverage_2014': '100',
    #     'pcd_sector': 'ABDC'},
    #    {'asset': '4G',
    #     'asset_id': '7jd',
    #     'coverage_2014': '100',
    #     'pcd_sector': 'ABDC'},
    #    {'asset': '3G',
    #     'asset_id': '3je',
    #     'coverage_2014': '0',
    #     'pcd_sector': 'DEFG'},
    #    {'asset': '4G',
    #     'asset_id': '8js',
    #     'coverage_2014': '0',
    #     'pcd_sector': 'DEFG'},
    #    {'asset': '3G', 'asset_id': '4jd', 'pcd_sector': 'CDEF'}]
    

    【讨论】:

    • 这很好,感谢您提供的综合理论和完整的代码答案。
    【解决方案2】:

    您可以根据pcd_sector 创建一个查找字典,然后根据它更新您的原始字典列表:

    >>> import copy
    >>> lookup = { x['pcd_sector'] : x for x in l1 }
    >>> result = copy.deepcopy(l2)
    >>> for d in result:
    ...     d.update(lookup.get(d['pcd_sector'], {})) # golfed courtesy Ashwini Chaudhary
    ... 
    >>> result
    [{'pcd_sector': 'ABDC', 'asset': '3G', 'asset_id': '2gs', 'coverage_2014': '100'}, 
    {'pcd_sector': 'ABDC', 'asset': '4G', 'asset_id': '7jd', 'coverage_2014': '100'}, 
    {'pcd_sector': 'DEFG', 'asset': '3G', 'asset_id': '3je', 'coverage_2014': '0'}, 
    {'pcd_sector': 'DEFG', 'asset': '4G', 'asset_id': '8js', 'coverage_2014': '0'},
    {'pcd_sector': 'CDEF', 'asset': '3G', 'asset_id': '4jd'}]
    

    【讨论】:

    • 感谢 Coldspeed 的建议回答。最后我选择了 Eric 的答案,因为它提供了理论和完整的代码部分。
    【解决方案3】:

    使用pandas的解决方案:

    import pandas as pd
    
    df1 = pd.DataFrame(l1)
    df2 = pd.DataFrame(l2)
    dfr = df1.join(df2, how='outer')
    print(dfr)
    

    输出:

      coverage_2014 pcd_sector asset asset_id
    0           100       ABDC    3G      2gs
    1           100       ABDC    4G      7jd
    2             0       DEFG    3G      3je
    3             0       DEFG    4G      8js
    4           NaN       CDEF    3G      4jd
    

    如果你又想把它当作字典:

    result = dfr.to_dict('records')
    print(result)
    

    输出(添加换行符):

    [{'coverage_2014': '100', 'pcd_sector': 'ABDC', 'asset': '3G', 'asset_id': '2gs'},
     {'coverage_2014': '100', 'pcd_sector': 'ABDC', 'asset': '4G', 'asset_id': '7jd'},
     {'coverage_2014': '0', 'pcd_sector': 'DEFG', 'asset': '3G', 'asset_id': '3je'},
     {'coverage_2014': '0', 'pcd_sector': 'DEFG', 'asset': '4G', 'asset_id': '8js'},
     {'coverage_2014': nan, 'pcd_sector': 'CDEF', 'asset': '3G', 'asset_id': '4jd'}]
    

    【讨论】:

    • 不错。您不需要指定用于查找的列吗?
    • 您可以将列显式传递给 on 关键字参数,但我的印象是不这样做会自动在数据帧之间找到匹配的列名,这就是代码的行为方式.但是,the documentation 似乎另有说明(即使用索引),所以我现在不确定...
    猜你喜欢
    • 2017-11-30
    • 1970-01-01
    • 2018-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    相关资源
    最近更新 更多