在Python 3中,将一组字典按相同值分组

4
给定一个字典列表:
players= [
   { "name": 'matt', 'school': 'WSU', 'homestate': 'CT', 'position': 'RB' },
   { "name": 'jack', 'school': 'ASU', 'homestate': 'AL', 'position': 'QB' },
   { "name": 'john', 'school': 'WSU', 'homestate': 'MD', 'position': 'LB' },
   { "name": 'kevin', 'school': 'ALU', 'homestate': 'PA', 'position': 'LB' },
   { "name": 'brady', 'school': 'UM', 'homestate': 'CA', 'position': 'QB' },
]

我该如何将它们按照匹配字典值分组,以便输出以下内容:

匹配值1:

姓名:[马特,约翰,凯文],

学校:[WSU,WSU,ALU],

家乡:[CT,MD,PA]

职位:[RB,LB,LB]

匹配值2:

姓名:[杰克,布雷迪],

学校:[ASU,UM],

家乡:[AL,CA]

职位:[QB,QB]

请注意,匹配值是任意的;也就是说,它可以在任何地方找到。也许在schoolposition中,或者两者都有。

我尝试通过以下方式进行分组:

from collections import defaultdict

result_dictionary = {}

for i in players:
    for key, value in i.items():
        result_dictionary.setdefault(key, []).append(value)

这将产生:

{'name': ['matt', 'jack', 'john', 'kevin', 'brady'], 
 'school': ['WSU', 'ASU', 'WSU', 'ALU', 'UM'], 
 'homestate': ['CT', 'AL', 'MD', 'PA', 'CA'], 
 'position': ['RB', 'QB', 'LB', 'QB', 'QB']}

但我卡在如何进一步操作输出以匹配上述所需输出的问题上,我相信有更好、更简单的方法来处理它。


如果您有选择的话,我建议您使用pandas。您可以轻松地进行分组。 - Arpit Solanki
匹配的值是任意的,也就是说,它可以在任何地方找到。也许在学校里,也许在职位上,或者两者都有。这并不清楚。你能给出一些例子来澄清吗? - juanpa.arrivillaga
@juanpa.arrivillaga,我已编辑问题以澄清它。 - Yuka Langbuana
我不确定这里的规则是什么(如果Matt和John去了同一所学校,但Matt和Jack打了同一个位置怎么办?你会有一个Matt&John组和一个Matt&Jack组吗?或者将它们合并成一个组,即使John&Jack没有共同之处?或者随意选择一个人将Matt放在哪个组中?或者非随意地选择(尝试最大化或最小化组数,也许)?或者...? - abarnert
如果这个问题的答案意味着不应该将玩家放入某种等价类样式的分区中:那么如果马特和约翰去了同一所学校并且还打了同一个位置?有一个马特和约翰组,还是两个,或者两种都可以接受? - abarnert
显示剩余11条评论
2个回答

3

只需使用您已经导入的 collections.defaultdict

In [21]: from collections import defaultdict
    ...: result = defaultdict(lambda: defaultdict(list))
    ...: for d in players:
    ...:     for k,v in d.items():
    ...:         result[d['school']][k].append(v)
    ...:

In [22]: result
Out[22]:
defaultdict(<function __main__.<lambda>>,
            {'ASU': defaultdict(list,
                         {'homestate': ['AL'],
                          'name': ['jack'],
                          'position': ['QB'],
                          'school': ['ASU']}),
             'WSU': defaultdict(list,
                         {'homestate': ['CT', 'MD'],
                          'name': ['matt', 'john'],
                          'position': ['RB', 'LB'],
                          'school': ['WSU', 'WSU']})})

如果匹配值是任意的,比如说它可以在“家乡”或“学校”中找到。你该怎么处理? - Yuka Langbuana
@YukaLangbuana 如何访问适当的值?我不明白你的意思。 - juanpa.arrivillaga
我的错误,我编辑了问题以澄清我的问题。 - Yuka Langbuana

1
你可以找到最常出现的标题值,并将后者作为进一步分组的焦点:
import itertools
players= [
  { "name": 'matt', 'school': 'WSU', 'homestate': 'CT', 'position': 'RB' },
  { "name": 'jack', 'school': 'ASU', 'homestate': 'AL', 'position': 'QB' },
  { "name": 'john', 'school': 'WSU', 'homestate': 'MD', 'position': 'LB' },
  { "name": 'kevin', 'school': 'ALU', 'homestate': 'PA', 'position': 'S' },
  { "name": 'brady', 'school': 'UM', 'homestate': 'CA', 'position': 'QB' },
]
headers = ['name', 'school', 'homestate', 'position'] 
final_header = [[a, max(b, key=lambda x:b.count(x))] for a, b in zip(headers, zip(*[[i[b] for b in headers] for i in players])) if len(set(b)) < len(b)]
d = [[list(b) for _, b in itertools.groupby(filter(lambda x:x[i] == c, players), key=lambda x:x[i])][0] for i, c in final_header]
last_results = {'pattern {}'.format(i):{d[0][0]:[j[-1] for j in d] for c, d in zip(headers, zip(*map(dict.items, h)))} for i, h in enumerate(d, start=1)}

输出:

{'pattern 2': 
  {'homestate': ['AL', 'CA'], 
  'school': ['ASU', 'UM'], 
  'name': ['jack', 'brady'], 
  'position': ['QB', 'QB']}, 

'pattern 1': 
    {'homestate': ['CT', 'MD'], 
    'school': ['WSU', 'WSU'], 
    'name': ['matt', 'john'], 
    'position': ['RB', 'LB']}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接