代码之家  ›  专栏  ›  技术社区  ›  Harrison

基于匹配值的词典合并列表

  •  1
  • Harrison  · 技术社区  · 8 年前

    我有一组类似的数据:

    trades =  [{'ORDERID': 123, 'LEAVESQTY': 2200}, 
                {'ORDERID': 123, 'LEAVESQTY': 500}, 
                {'ORDERID': 456, 'LEAVESQTY': 100}, 
                {'ORDERID': 789, 'LEAVESQTY': 300}]
    

    我正在寻找一种有效的方法来找到 LEAVESQTY 每次匹配 ORDERID 在字典列表中。

    例如,我对这个例子的期望结果是:

    output = [{'ORDERID': 123, 'LEAVESQTY': 5000},
              {'ORDERID': 456, 'LEAVESQTY': 100},
              {'ORDERID': 789, 'LEAVESQTY': 300}]
    

    我尝试使用与基于匹配键值合并字典的类似问题相同的方法,我只是在基于值合并时遇到问题。

    4 回复  |  直到 8 年前
        1
  •  1
  •   jpp    8 年前

    你可以用 collections.defaultdict 构造字典到列表的映射。

    然后使用字典理解计算每个列表的最小值。

    from collections import defaultdict
    
    trades =  [{'ORDERID': 123, 'LEAVESQTY': 2200}, 
               {'ORDERID': 123, 'LEAVESQTY': 500}, 
               {'ORDERID': 456, 'LEAVESQTY': 100}, 
               {'ORDERID': 789, 'LEAVESQTY': 300}]
    
    d = defaultdict(list)
    
    for item in trades:
        d[item['ORDERID']].append(item['LEAVESQTY'])
    
    res = [{'ORDERID': k, 'LEAVESQTY': min(v)} for k, v in d.items()]
    
    [{'LEAVESQTY': 500, 'ORDERID': 123},
     {'LEAVESQTY': 100, 'ORDERID': 456},
     {'LEAVESQTY': 300, 'ORDERID': 789}]
    
        2
  •  2
  •   jpp    8 年前

    这里有一种方法 sorted 和 toolz.unique .我们的想法是 LEAVESQTY 然后删除重复项 ORDERID .

    如果您没有访问 toolz 库,逻辑与 unique_everseen recipe 发现于 itertools 文件。

    from operator import itemgetter
    from toolz import unique
    
    trades =  [{'ORDERID': 123, 'LEAVESQTY': 2200}, 
               {'ORDERID': 123, 'LEAVESQTY': 500}, 
               {'ORDERID': 456, 'LEAVESQTY': 100}, 
               {'ORDERID': 789, 'LEAVESQTY': 300}]
    
    sorter = sorted(trades, key=itemgetter('LEAVESQTY'))
    res = list(unique(sorter, key=itemgetter('ORDERID')))
    
    print(res)
    
    [{'LEAVESQTY': 100, 'ORDERID': 456},
     {'LEAVESQTY': 300, 'ORDERID': 789},
     {'LEAVESQTY': 500, 'ORDERID': 123}]
    
        3
  •  1
  •   Rakesh    8 年前

    使用简单的迭代。

    演示:

    d = {}
    
    trades =  [{'ORDERID': 123, 'LEAVESQTY': 2200}, 
                {'ORDERID': 123, 'LEAVESQTY': 500}, 
                {'ORDERID': 456, 'LEAVESQTY': 100}, 
                {'ORDERID': 789, 'LEAVESQTY': 300}]
    
    for i in trades:
        if i['ORDERID'] not in d:
            d[i["ORDERID"]] = i
        else:
            if d[i["ORDERID"]]["LEAVESQTY"] > i["LEAVESQTY"]:
                d[i["ORDERID"]]["LEAVESQTY"] = i["LEAVESQTY"]
    print(d.values())
    

    输出:

    [{'ORDERID': 456, 'LEAVESQTY': 100}, {'ORDERID': 123, 'LEAVESQTY': 500}, {'ORDERID': 789, 'LEAVESQTY': 300}]
    
        4
  •  1
  •   zipa    8 年前

    你可以用 itertools.groupby() 以下内容:

    from itertools import groupby
    
    common = lambda x: x['ORDERID']
    
    grouped = groupby(sorted(trades, key=common), key=common)
    
    output = [min(group) for key, group in grouped]
    
    output
    #[{'LEAVESQTY': 500, 'ORDERID': 123},
    # {'LEAVESQTY': 100, 'ORDERID': 456},
    # {'LEAVESQTY': 300, 'ORDERID': 789}]
    

    编辑

    排序是必要的,正如@jpp建议的那样,这样才能工作,否则,如果数据如下所示,它将生成重复的键:

    #trades =  [{'ORDERID': 789, 'LEAVESQTY': 400},
    #           {'ORDERID': 123, 'LEAVESQTY': 2200}, 
    #            {'ORDERID': 123, 'LEAVESQTY': 500}, 
    #            {'ORDERID': 456, 'LEAVESQTY': 100}, 
    #            {'ORDERID': 789, 'LEAVESQTY': 300},
    #            {'ORDERID': 789, 'LEAVESQTY': 150}]