重新组合或重新组织字典中的键?

时间:2018-01-24 02:37:51

标签: python list dictionary grouping reorganize

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

[ {'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.groupbydict.setdefault()作为建议here,但无法完全得到我想要的内容。我怎么能这样做?

7 个答案:

答案 0 :(得分: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}]}
]

答案 1 :(得分:1)

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

答案 2 :(得分: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']})

答案 3 :(得分: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

答案 4 :(得分:0)

如果您想使用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'}]

答案 5 :(得分: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是dicts的输入列表。

选项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")

此处从结果组中删除重复键。删除项目将改变嵌套的词典。为了保留以前嵌套的dicts的某种程度,制作深层照片,即。看到可选行。

答案 6 :(得分: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'}]}