Python 重新组合或重新组织dict中的键?

Python 重新组合或重新组织dict中的键?,python,list,dictionary,grouping,reorganize,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': 'Engl

我在一个列表中有一个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'}]
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'])})
我想将其重新组合或重组如下:

[ {'subject': 'Math',
  'Results': [{'name': 'Joe','score':98}, {'name':'Bob', 'score':90}]},
  {'subject': 'English',
  'Results': [{'name': 'Jane','score':95}, {'name':'Bill', 'score':88}]}
]
我试着按照建议使用
itertools.groupby
dict.setdefault()
,但不能完全得到我想要的。如何进行此操作?

使用一个小循环,您可以按如下方式进行分组:

[ {'name': 'Joe', 
   'score': 98,
   'subject': 'Math'},
{'name': 'Bob', 
   'score': 90,
   'subject': 'Math'},
{'name': 'Bill', 
   'score': 88,
   'subject': 'English'},
{'name': 'Jane', 
   'score': 95,
   'subject': 'English'}]
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'])})
代码: 要在分组后获取其他输出格式,请执行以下操作:

grouped = [{'subject': k, 'Results': v} for k, v in grouped.items()]
测试代码: 结果:
您需要遍历旧列表,并将每个元素重新格式化为新元素

#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']})

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

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)
工作代码:

请看一下,下面的代码可能会对您有所帮助

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

如果要使用
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'}]
选择1

以下是一种标准方法:

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代表k,g在itertools.groupby(iterable,key)]
,则这里的
g
简单地用过滤字典替换
lst
是DICT的输入列表

选择2

是一个第三方配方,可扩展以允许更改结果组:

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

此处将从生成的组中删除重复的键。删除项将使嵌套字典发生变化。要保留以前嵌套的dict的某些级别,请制作deepcopies,例如,请参见可选行

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

[ {'name': 'Joe', 
   'score': 98,
   'subject': 'Math'},
{'name': 'Bob', 
   'score': 90,
   'subject': 'Math'},
{'name': 'Bill', 
   'score': 88,
   'subject': 'English'},
{'name': 'Jane', 
   'score': 95,
   'subject': 'English'}]
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'}]}

似乎熊猫的
groupby
函数可能会有帮助,“不能完全得到我想要的”在一个问题上不是很有用。为您尝试的内容提供一个示例,包括示例输入和预期输出(可以是您在此处提供的)以及观察到的(意外的)输出,我们可以提供帮助来修复它。一般来说,“为我编写代码”问题是不受欢迎的。注意:如果性能很重要,
setdefault
具有非常量文本默认值可能会浪费大量输入(在这种情况下,无论是否需要,每次调用都必须创建默认的新空
列表
)。使
grouped=collections.defaultdict(list)
,然后执行
grouped[score['subject']]。append(…)
将更快/更干净(
defaultdict
仅当请求的键不存在时才惰性地创建默认值);如果您想在之后删除默认行为,只需在末尾执行
grouped=dict(grouped)
即可将其转换回。这接近所需的结果。额外的关键项仍会出现在生成的dict中。