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

Python 字典列表中按特定键分组的键值之和,python,list,dictionary,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', 'invo

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

[
    {'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} 
] 

请告诉我如何才能达到同样的效果,因为您没有提供任何关于您以前尝试的信息。我假设这个问题是关于从哪里开始的

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


总和={
“内部”:{“发票”:…,“初始工程量清单”:…},
# …
}
特别适合这种情况的是defaultdict:

从集合导入defaultdict
总和=defaultdict(lamdba:defaultdict(lambda:0))
使用此定义,您可以添加如下值:

sums['internal']['invoited']+=1_值

您可以像这样使用
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}]
这里有一行:)

这是这一行的等效代码

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)
再见

比这里已经发布的许多解决方案要不那么引人注目,但非常清楚

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}]

希望这也有帮助

祝你今天愉快,

安东尼诺

你以前解决这个问题的尝试是什么样子的?你可能希望熊猫来做这种手术。您可以使用常规代码执行此操作,但这正是pandas的用途。@PaulRooney[{'scope':u'internal','Invocated':5000,'initial_boq':4300}{'scope':u'external','Invocated':650,'initial_boq':2000}{'scope':u'both','Invocated':5000,'initial_boq':7000}它部分工作,我不知道为什么它给出了同一个键的两个dict的输出,即scope。感谢您的努力这可能是因为元素列表没有按
范围
属性排序。它在您的示例代码中。如果首先对
groupby
的输入进行排序,则该操作将起作用。使用
groupby(sorted(d,key=itemgetter('scope'))、key=itemgetter('scope'))
之类的代码会变得有点笨拙。因此,自定义分组函数可能是最好的。
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}]