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

时间:2019-05-22 07:48:50

标签: python list dictionary group-by

如何基于多个关键要素将词典列表分组为唯一词典列表?

    if (message.content === '$uwu') {
      message.channel.send('say uwu! - i will count how many people say uwu in 30 seconds')
        .then(() => {
          message.channel.awaitMessages(response => response.content === 'uwu', {
              max: 100000000,
              time: 30000,
              errors: ['time'],
            })
            .then((collected) => {
                if (collected.size > 0  ) {
                    message.channel.send('no one said uwu :(');
              message.channel.send(`${collected.first.size} people said uwu`);
                }
            })
            .catch((collected) => {
                if (collected.size > 0) {
                    if (collected.size === 1) {
                    message.channel.send(`${collected.size} person said uwu!`);
                    }
                    else if (collected.size > 1) {
                        message.channel.send(`${collected.size} people said uwu!`);


                    }
                }
                else if (collected.size === 0) {
                    message.channel.send('no one said uwu :(')


                }
            });
        });
    }
  });

关键元素是“位置”和“ sku”。我想将具有相同关键元素的字典归为一个字典,其余具有不同值的关键将进入一个列表同一词典中的不同词典的组合。

预期输出:

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

我尝试对this进行必要的修改,但是我们有一个更好,更准确的解决方案吗?

3 个答案:

答案 0 :(得分:1)

使用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'}]

答案 1 :(得分:0)

我已经修改了上面的答案,它给了我预期的输出。顺便说一句,谢谢@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)

答案 2 :(得分:0)

您也可以使用嵌套列表推导和一些讨厌的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。但是,此命令会在此过程中破坏原始的datai.pop()调用会对原始字典起作用)。

内部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会在此处短路)。

其余只是输入。不幸的是,我不知道将其格式化为更好的形状。