按特定键分组的字典列表中的键值总和

时间:2019-08-20 05:43:36

标签: python list dictionary

我想对按范围分组的键的值求和

[
    {'scope': u'internal', 'invoiced': 1000, 'initial_boq': 2800}
    {'scope': u'internal', 'invoiced': 2000, 'initial_boq': 1000}    
    {'scope': u'internal', 'invoiced': 2000, 'initial_boq': 500}
    {'scope': u'external', 'invoiced': 500,  'initial_boq': 1800}
    {'scope': u'external', 'invoiced': 150,  'initial_boq': 200}
    {'scope': u'both',     'invoiced': 5000, 'initial_boq': 7000}
]

我们如何获得dict对范围进行分组的键之和:

预期输出

[ 
   {'scope': u'internal', 'invoiced': 5000, 'initial_boq': 4300}, 
   {'scope': u'external', 'invoiced': 650, 'initial_boq': 2000},
   {'scope': u'both', 'invoiced': 5000, 'initial_boq': 7000} 
] 

请让我知道如何实现相同的目标

5 个答案:

答案 0 :(得分:1)

由于您没有提供任何关于先前尝试的信息,因此我假设这个问题是关于从何开始的。

我要寻找的第一件事是使解决问题变得简单的数据结构。在这种情况下,我将创建一个求和字典:


sums = {
  'internal': {'invoiced': …, 'initial_boq': …},
  # …
}

特别适用于此的是defaultdict:

from collections import defaultdict

sums = defaultdict(lamdba: defaultdict(lambda:0))

使用此定义,您可以像这样添加值:

sums['internal']['invoiced'] += one_value

答案 1 :(得分:0)

您可以使用itertools.groupby,就像这样。带有附加功能可以汇总分组的项目。

from itertools import groupby
from operator import itemgetter


d = [
    {'scope': u'internal', 'invoiced': 1000, 'initial_boq': 2800},
    {'scope': u'internal', 'invoiced': 2000, 'initial_boq': 1000}, 
    {'scope': u'internal', 'invoiced': 2000, 'initial_boq': 500},
    {'scope': u'external', 'invoiced': 500,  'initial_boq': 1800},
    {'scope': u'external', 'invoiced': 150,  'initial_boq': 200},
    {'scope': u'both',     'invoiced': 5000, 'initial_boq': 7000},
]


def getsummed(scope, elems):

    d = {'scope': scope, 'invoiced': 0, 'initial_boq': 0}

    for e in elems:
        d['invoiced'] += e['invoiced']
        d['initial_boq'] += e['initial_boq']
    return d


def sortedgroupby(iterable, key):

    return groupby(sorted(iterable, key=key), key=key)


print([getsummed(gpr, groups) for gpr, groups in sortedgroupby(d, key=itemgetter('scope'))])

结果是

[{'scope': 'internal', 'invoiced': 5000, 'initial_boq': 4300}, {'scope': 'external', 'invoiced': 650, 'initial_boq': 2000}, {'scope': 'both', 'invoiced': 5000, 'initial_boq': 7000}]

答案 2 :(得分:0)

list1 = [
    {'scope': u'internal', 'invoiced': 1000, 'initial_boq': 2800},
    {'scope': u'internal', 'invoiced': 2000, 'initial_boq': 1000},   
    {'scope': u'internal', 'invoiced': 2000, 'initial_boq': 500},
    {'scope': u'external', 'invoiced': 500,  'initial_boq': 1800},
    {'scope': u'external', 'invoiced': 150,  'initial_boq': 200},
    {'scope': u'both',     'invoiced': 5000, 'initial_boq': 7000}
]
tempJson = {}
finalList = []

for eachScopeJson in list1:
    if eachScopeJson['scope'] in tempJson:
        tempJson[eachScopeJson['scope']]['invoiced'] = tempJson[eachScopeJson['scope']]['invoiced'] + eachScopeJson['invoiced']
        tempJson[eachScopeJson['scope']]['initial_boq'] = tempJson[eachScopeJson['scope']]['initial_boq'] + eachScopeJson['initial_boq']
    else:
        tempJson[eachScopeJson['scope']] = {}
        tempJson[eachScopeJson['scope']]['invoiced'] = 0 + eachScopeJson['invoiced']
        tempJson[eachScopeJson['scope']]['initial_boq'] = 0 + eachScopeJson['initial_boq']


for eachKey in tempJson:
    finalList.append({'scope':eachKey,'invoiced':tempJson[eachKey]['invoiced'],'initial_boq':tempJson[eachKey]['initial_boq']})


print tempJson

答案 3 :(得分:0)

这里是单线:)

from collections import Counter
from itertools import groupby

key = lambda d: d['scope']
res = [dict(sum((Counter({k:v for k,v in grp.items() if k!='scope'}) for grp in grps), Counter()), scope=scope) for scope,grps in groupby(sorted(lst, key=key), key=key)]
print (res)

[{'invoiced': 5000, 'initial_boq': 7000, 'scope': 'both'}, {'invoiced': 650, 'initial_boq': 2000, 'scope': 'external'}, {'invoiced': 5000, 'initial_boq': 4300, 'scope': 'internal'}]

这是单线的等效代码

key = lambda d: d['scope']
res = []
for scope,grps in groupby(sorted(lst, key=key), key=key):
    c = Counter()
    for grp in grps:
         grp.pop('scope')
         c += Counter(grp)

    res.append(dict(c, scope=scope))

pprint(res)

答案 4 :(得分:0)

Ciao

比这里已经发布的许多解决方案少得多,但非常清晰

def removeDuplicatedScopesFrom(startingData): 
    differentScopes = [] 
    for x in startingData:
        scope = x["scope"]
        if scope not in differentScopes: 
            differentScopes.append(scope) 
    return differentScopes

def composeDictionaryElement(scope, invoiced, initial_boq):
    return("{'scope': u'" + scope + "', 'invoiced': " + str(invoiced) + ", 'initial_boq': " + str(initial_boq) + "}")

def main():
    var = [
        {'scope': u'internal', 'invoiced': 1000, 'initial_boq': 2800},
        {'scope': u'internal', 'invoiced': 2000, 'initial_boq': 1000},   
        {'scope': u'internal', 'invoiced': 2000, 'initial_boq': 500},
        {'scope': u'external', 'invoiced': 500,  'initial_boq': 1800},
        {'scope': u'external', 'invoiced': 150,  'initial_boq': 200},
        {'scope': u'both',     'invoiced': 5000, 'initial_boq': 7000}
    ]

    # empty list for the final result
    finalList = []
    # identifying the different scopes involved
    scopes = removeDuplicatedScopesFrom(var)

    # scanning the input and joining data from the same scope
    for scope in scopes:

        # resetting values for each different scope
        invoiced = 0;
        initial_boq = 0;

        # checking all the elements in the list
        for y in var:
            if y["scope"] == scope:
                invoiced = invoiced + y["invoiced"]
                initial_boq = initial_boq + y["initial_boq"]

        # when list is over we ask to compose the related dictionary element
        finalDictionaryElement = composeDictionaryElement(scope, invoiced, initial_boq)
        # adding it to the final list
        finalList.append(finalDictionaryElement)

    # results out without surrounding quotes
    print("[%s]" % (', '.join(finalList)))

if __name__== "__main__":
    main()

输出

[{'scope': u'internal', 'invoiced': 5000, 'initial_boq': 4300}, {'scope': u'external', 'invoiced': 650, 'initial_boq': 2000}, {'scope': u'both', 'invoiced': 5000, 'initial_boq': 7000}]


希望也有帮助

今天过得好,
安东尼诺