2

我在一个列表中有一个字典,目前是这样的:

[ {'name': 'Joe', 
   'score': 98,
   'subject': 'Math'},
{'name': 'Bob', 
   'score': 90,
   'subject': 'Math'},
{'name': 'Bill', 
   'score': 88,
   'subject': 'English'},
{'name': 'Jane', 
   'score': 95,
   'subject': 'English'}]

我想重组或重组如下:

[ {'subject': 'Math',
  'Results': [{'name': 'Joe','score':98}, {'name':'Bob', 'score':90}]},
  {'subject': 'English',
  'Results': [{'name': 'Jane','score':95}, {'name':'Bill', 'score':88}]}
]

我尝试按照这里的建议使用itertools.groupbyand ,但不能完全得到我想要的。我怎样才能做到这一点?dict.setdefault()

4

7 回答 7

4

使用一个小循环,dict.setdefault您可以像这样进行分组:

代码:

grouped = {}
for score in scores:
    grouped.setdefault(score['subject'], []).append(
        {k: v for k, v in score.items() if k != 'subject'})

分组后获取其他输出格式:

grouped = [{'subject': k, 'Results': v} for k, v in grouped.items()]

测试代码:

scores = [
    {'name': 'Joe',
       'score': 98,
       'subject': 'Math'},
    {'name': 'Bob',
       'score': 90,
       'subject': 'Math'},
    {'name': 'Bill',
       'score': 88,
       'subject': 'English'},
    {'name': 'Jane',
       'score': 95,
       'subject': 'English'}]

grouped = {}
for score in scores:
    grouped.setdefault(score['subject'], []).append({
        k: v for k, v in score.items() if k != 'subject'})

print([{'subject': k, 'Results': v} for k, v in grouped.items()])

结果:

[
    {'subject': 'Math', 
     'Results': [{'name': 'Joe', 'score': 98}, {'name': 'Bob', 'score': 90}]}, 
    {'subject': 'English', 
     'Results': [{'name': 'Bill', 'score': 88}, {'name': 'Jane', 'score': 95}]}
]
于 2018-01-24T02:45:48.530 回答
2

看看itertools.groupby,然后下面的代码可能会对你有所帮助。

[{'subject': k, 'Results': list(g)} for k, g in itertools.groupby(a, key=itemgetter('subject'))]

样本输出:

[{'Results': [{'score': 98, 'name': 'Joe', 'subject': 'Math'}, {'score': 90, 'name': 'Bob', 'subject': 'Math'}], 'subject': 'Math'}, {'Results': [{'score': 88, 'name': 'Bill', 'subject': 'English'}, {'score': 95, 'name': 'Jane', 'subject': 'English'}], 'subject': 'English'}]
于 2018-01-24T03:02:07.513 回答
0

在一行中,您可以执行以下操作:

data=[ {'name': 'Joe',
   'score': 98,
   'subject': 'Math'},
{'name': 'Bob',
   'score': 90,
   'subject': 'Math'},
{'name': 'Bill',
   'score': 88,
   'subject': 'English'},
{'name': 'Jane',
   'score': 95,
   'subject': 'English'}]

import itertools

print({i:list(j) for i,j in itertools.groupby(data,key=lambda x:x['subject'])})

输出:

{'English': [{'subject': 'English', 'score': 88, 'name': 'Bill'}, {'subject': 'English', 'score': 95, 'name': 'Jane'}], 'Math': [{'subject': 'Math', 'score': 98, 'name': 'Joe'}, {'subject': 'Math', 'score': 90, 'name': 'Bob'}]}
于 2018-01-25T05:03:47.420 回答
0

如果你想使用 a collections.defaultdict(),你可以这样做:

from collections import defaultdict
from pprint import pprint

scores = [{'name': 'Joe', 
           'score': 98,
           'subject': 'Math'},
          {'name': 'Bob', 
           'score': 90,
           'subject': 'Math'},
          {'name': 'Bill', 
           'score': 88,
           'subject': 'English'},
          {'name': 'Jane', 
           'score': 95,
           'subject': 'English'}]

result = defaultdict(list)
for score in scores:
    temp = {k: _ for k, _ in score.items() if k != 'subject'}
    result[score['subject']].append(temp)

pprint([{'subject' : k, 'Results': v} for k, v in result.items()])

这使:

[{'Results': [{'name': 'Joe', 'score': 98}, {'name': 'Bob', 'score': 90}],
  'subject': 'Math'},
 {'Results': [{'name': 'Bill', 'score': 88}, {'name': 'Jane', 'score': 95}],
  'subject': 'English'}]
于 2018-01-24T03:32:25.327 回答
0

选项1

这是一个标准itertools.groupby方法:

key = "subject"
[{key: k, "Result": {k_: v for d in g for k_, v in d.items() if k_ != key}} for k, g in it.groupby(lst, lambda x: x[key])]

为简单起见,如果给定的形式[k: g for k, g in itertools.groupby(iterable, key)],这里g只是用过滤的字典理解代替。 lst是字典的输入列表。

选项 2

more_itertools.groupby_transform是第三方配方,可扩展itertools.groupby以允许更改结果组:

import copy

import more_itertools as mit


def get_scores(iterable, key):
    """Return resulting ditctionaries grouped by key."""
    iterable = copy.deepcopy(iterable)                            # optional
    kfunc = lambda x: x[key]
    def vfunc(x):
        del x[key]
        return x
    return [{key: k, "Result": list(g)} for k, g in mit.groupby_transform(iterable, keyfunc=kfunc, valuefunc=vfunc)]


get_scores(lst, "subject")

此处从结果组中删除重复键。删除项目将改变嵌套字典。为了保留以前的嵌套字典的某些级别,请进行深度复制,即参见可选行。

于 2018-01-24T05:04:12.473 回答
0

您将需要遍历旧列表并将每个元素重新格式化为新列表

#first we need to create the newList in the general format that you want

newList = [{'subject':'math','results':[]},{'subject':'english','results':[]}]

#then we iterate through the elements in the old list and put them into the new list with the new formatting

for i in oldList:

    element = 0 if i['subject']=='math' else 'english' #because, in your post, you ordered them this way

    #then we need to append the element to the results list

    newList[element]['results'].append({'name':i['name'],'score':i['score']})
于 2018-01-24T02:57:28.400 回答
0

在处理从某些字典数据派生的自定义对象时,我喜欢这种语法:

o = [ {'name': 'Joe', 
   'score': 98,
   'subject': 'Math'},
{'name': 'Bob', 
   'score': 90,
   'subject': 'Math'},
{'name': 'Bill', 
   'score': 88,
   'subject': 'English'},
{'name': 'Jane', 
   'score': 95,
   'subject': 'English'}]

r = []
for a in set([b['subject'] for b in o]):
  r.append({
      'subject': a, 
      'Results': [{'name':c['name'], 'score':c['score']} for c in o if c['subject']==a ],
  })

print(r)

工作代码:repl.it

于 2018-01-24T02:58:48.107 回答