如何通过多个键对数组进行分组?

时间:2015-08-12 03:11:06

标签: python arrays dictionary

我喜欢一个函数,它可以将字典列表分组到字典的子列表中,具体取决于所有字典共有的任意键集。

例如,我希望将以下列表分组到字典的子列表中,具体取决于某组键

l = [{'name':'b','type':'new','color':'blue','amount':100},{'name':'c','type':'new','color':'red','amount':100},{'name':'d','type':'old','color':'gold','amount':100},{'name':'e','type':'old','color':'red','amount':100},
{'name':'f','type':'old','color':'red','amount':100},{'name':'g','type':'normal','color':'red','amount':100}]

如果我想按类型分组,将产生以下列表,其中包含每个子列表具有相同类型的子列表:

[[{'name':'b','type':'new','color':'blue','amount':100},{'name':'c','type':'new','color':'red','amount':100}],[{'name':'d','type':'old','color':'gold','amount':100},{'name':'e','type':'old','color':'red','amount':100},
{'name':'f','type':'old','color':'red','amount':100}],[{'name':'g','type':'normal','color':'red','amount':100}]]

如果我想按类型和颜色进行分组,则会在列表包含具有相同类型和颜色的子列表时产生以下结果:

[[{'name':'b','type':'new','color':'blue','amount':100}],[{'name':'c','type':'new','color':'red','amount':100}],[{'name':'d','type':'old','color':'gold','amount':100}],[{'name':'e','type':'old','color':'red','amount':100},
{'name':'f','type':'old','color':'red','amount':100}],[{'name':'g','type':'normal','color':'red','amount':100}]]

我理解以下功能可以按一个键分组,但我想按多个键分组:

 def group_by_key(l,i):

      l = [list(grp) for key, grp in itertools.groupby(sorted(l, key=operator.itemgetter(i)), key=operator.itemgetter(i))]

这是我尝试使用上面的group_by_function

 def group_by_multiple_keys(l,*keys):
      for key in keys:
          l = group_by_key(l,key)
          l = [item for sublist in l for item in sublist]
      return l 

问题在于它在用密钥对其进行分组之后将其取消组合。相反,我想通过另一个密钥对其进行重新分组,并且仍然有一个子列表列表。

1 个答案:

答案 0 :(得分:2)

itertools.groupby() + operator.itemgetter()会做你想要的。 groupby()采用可迭代和键函数,并通过将每个项传递给键函数返回的值对iterable中的项进行分组。 itemgetter()是一个返回函数的工厂,它从传递给它的任何项中获取指定的项。

from __future__ import print_function

import pprint

from itertools import groupby
from operator import itemgetter


def group_by_keys(iterable, keys):
    key_func = itemgetter(*keys)

    # For groupby() to do what we want, the iterable needs to be sorted
    # by the same key function that we're grouping by.
    sorted_iterable = sorted(iterable, key=key_func)

    return [list(group) for key, group in groupby(sorted_iterable, key_func)]


dicts = [
    {'name': 'b', 'type': 'new', 'color': 'blue', 'amount': 100},
    {'name': 'c', 'type': 'new', 'color': 'red', 'amount': 100},
    {'name': 'd', 'type': 'old', 'color': 'gold', 'amount': 100},
    {'name': 'e', 'type': 'old', 'color': 'red', 'amount': 100},
    {'name': 'f', 'type': 'old', 'color': 'red', 'amount': 100},
    {'name': 'g', 'type': 'normal', 'color': 'red', 'amount': 100}
    ]

示例:

>>> pprint.pprint(group_by_keys(dicts, ('type',)))
[[{'amount': 100, 'color': 'blue', 'name': 'b', 'type': 'new'},
  {'amount': 100, 'color': 'red', 'name': 'c', 'type': 'new'}],
 [{'amount': 100, 'color': 'gold', 'name': 'd', 'type': 'old'},
  {'amount': 100, 'color': 'red', 'name': 'e', 'type': 'old'},
  {'amount': 100, 'color': 'red', 'name': 'f', 'type': 'old'}],
 [{'amount': 100, 'color': 'red', 'name': 'g', 'type': 'normal'}]]
>>> 
>>> pprint.pprint(group_by_keys(dicts, ('type', 'color')))
[[{'amount': 100, 'color': 'blue', 'name': 'b', 'type': 'new'}],
 [{'amount': 100, 'color': 'red', 'name': 'c', 'type': 'new'}],
 [{'amount': 100, 'color': 'gold', 'name': 'd', 'type': 'old'}],
 [{'amount': 100, 'color': 'red', 'name': 'e', 'type': 'old'},
  {'amount': 100, 'color': 'red', 'name': 'f', 'type': 'old'}],
 [{'amount': 100, 'color': 'red', 'name': 'g', 'type': 'normal'}]]