如何根据两个值对词典进行分组?

2024-10-06 03:42:40 发布

您现在位置:Python中文网/ 问答频道 /正文

如何将字典列表分组为基于多个关键元素的唯一字典列表?你知道吗

in = [{'location': 'eastus', 'sku': 'S', 'term': 'P1', 'scope': '1'},
         {'location': 'india', 'sku': 'a', 'term': 'P1', 'scope': '2'},
         {'location': 'eastus', 'sku': 'S', 'term': 'P3', 'scope': '3'},
         {'location': 'india', 'sku': 'f', 'term': 'P1', 'scope': '4'},
         {'location': 'japan', 'sku': 'a', 'term': 'P1', 'scope': '5'},
         {'location': 'india', 'sku': 'a', 'term': 'P3', 'scope': '6'}
      ]

关键元素是“location”和“sku”。我想将具有相同关键元素的字典分组到一个dict中,其中具有不同值的其余键将放入同一dict中的一个单独字典列表中

预期产量:

out = [{'location': 'eastus', 'sku': 'S', 'new_key': [
                                                     {'term': 'P1', 'scope': '1'}, 
                                                     {'term': 'P3', 'scope': '3'}
                                                    ]},
           {'location': 'india', 'sku': 'a', 'new_key': [
                                                     {'term': 'P1', 'scope': '2'},
                                                     {'term': 'P3', 'scope': '6'}
                                                    ]},
           {'location': 'india', 'sku': 'f', 'term': 'P1', 'scope': '4'},
           {'location': 'japan', 'sku': 'a', 'term': 'P1', 'scope': '5'},
        ]

我试过this进行必要的修改,但我们有更好更准确的解决方案吗?你知道吗


Tags: 元素列表new字典locationdict关键scope
3条回答

使用itertools.groupby

例如:

from itertools import groupby

data = [{'location': 'eastus', 'sku': 'S', 'term': 'P1', 'scope': '1'},
         {'location': 'india', 'sku': 'a', 'term': 'P1', 'scope': '2'},
         {'location': 'eastus', 'sku': 'S', 'term': 'P3', 'scope': '3'},
         {'location': 'india', 'sku': 'f', 'term': 'P1', 'scope': '4'},
         {'location': 'japan', 'sku': 'a', 'term': 'P1', 'scope': '5'},
         {'location': 'india', 'sku': 'a', 'term': 'P3', 'scope': '6'}
      ]
result = []
for k, v in groupby(sorted(data, key=lambda x: (x["location"], x["sku"])), lambda x: (x["location"], x["sku"])):
    temp = dict(zip(('location', 'sku'), k))
    sub_value = list(v)
    if len(sub_value) == 1:
        temp.update(sub_value[0])
    else:
        temp.update({'new_key': sub_value})
    result.append(temp)

print(result)

输出:

[{'location': 'eastus',
  'new_key': [{'location': 'eastus', 'scope': '1', 'sku': 'S', 'term': 'P1'},
              {'location': 'eastus', 'scope': '3', 'sku': 'S', 'term': 'P3'}],
  'sku': 'S'},
 {'location': 'india',
  'new_key': [{'location': 'india', 'scope': '2', 'sku': 'a', 'term': 'P1'},
              {'location': 'india', 'scope': '6', 'sku': 'a', 'term': 'P3'}],
  'sku': 'a'},
 {'location': 'india', 'scope': '4', 'sku': 'f', 'term': 'P1'},
 {'location': 'japan', 'scope': '5', 'sku': 'a', 'term': 'P1'}]

我已经修改了上面的答案,它给了我预期的结果。顺便说一句,谢谢@rakesh

    from itertools import groupby
    result = []
    keys = ('location', 'sku')
    for k, v in groupby(sorted(lst, key=lambda x: (x["location"], x["sku"])), lambda x: (x["location"], x["sku"])):
        temp = dict(zip(keys, k))
        sub_value = list(v)
        if len(sub_value) == 1:
            temp.update({'new_key': sub_value[0]})
            list(map(temp['new_key'].pop, keys))
        else:
            temp.update({'new_key': sub_value})
            for i in temp['new_key']:
                list(map(i.pop, keys))
        result.append(temp)
    print(result)

您可以使用嵌套列表理解和一些讨厌的lambda来实现这一点:

from itertools import groupby
import pprint

pp=pprint.PrettyPrinter()

data = [{'location': 'eastus', 'sku': 'S', 'term': 'P1', 'scope': '1'},
         {'location': 'india', 'sku': 'a', 'term': 'P1', 'scope': '2'},
         {'location': 'eastus', 'sku': 'S', 'term': 'P3', 'scope': '3'},
         {'location': 'india', 'sku': 'f', 'term': 'P1', 'scope': '4'},
         {'location': 'japan', 'sku': 'a', 'term': 'P1', 'scope': '5'},
         {'location': 'india', 'sku': 'a', 'term': 'P3', 'scope': '6'}]

pp.pprint([(lambda k,g:k.update({"new_key":[(lambda i:i.pop("location") and i.pop("sku") and i)(item) for item in g]}) or k)(k,g) for k,g in groupby(sorted(data,key=lambda i:(i["location"],i["sku"])), lambda i:{"location":i["location"],"sku":i["sku"]})])

测试在这里:https://ideone.com/24bjKw。然而,这个函数在这个过程中破坏了原始的data(调用原始dict的工作)。你知道吗

内部lambda中的步骤链接是唯一棘手的部分:

lambda i:i.pop("location") and i.pop("sku") and i

使用and,因为pop返回它所发现的内容,所以这种方式短路求值不能干扰i将成为表达式的实际值。(如果对pop()找到密钥有疑问,可能是i.pop("...",True)

lambda k,g:k.update(...) or k

需要or,因为update()返回None(因此and会在这里短路)。你知道吗

剩下的只是打字。不幸的是,我不知道如何把它格式化成更好的形状。你知道吗

相关问题 更多 >