Pythonic方法将列表中的项目分组

Yuv*_*dam 2 python collections dictionary list

考虑一个dicts列表:

items = [
    {'a': 1, 'b': 9, 'c': 8},
    {'a': 1, 'b': 5, 'c': 4},
    {'a': 2, 'b': 3, 'c': 1},
    {'a': 2, 'b': 7, 'c': 9},
    {'a': 3, 'b': 8, 'c': 2}
]
Run Code Online (Sandbox Code Playgroud)

有没有pythonic方法来提取和分类这些项目的a字段,这样:

result = {
    1 : [{'b': 9, 'c': 8}, {'b': 5, 'c': 4}]
    2 : [{'b': 3, 'c': 1}, {'b': 7, 'c': 9}]
    3 : [{'b': 8, 'c': 2}]
}
Run Code Online (Sandbox Code Playgroud)

提到任何类似的Pythonic构建体都是值得赞赏的.

Ash*_*ary 6

用途itertools.groupby:

>>> from itertools import groupby
>>> from operator import itemgetter
>>> {k: list(g) for k, g in groupby(items, itemgetter('a'))}
{1: [{'a': 1, 'c': 8, 'b': 9},
     {'a': 1, 'c': 4, 'b': 5}],
 2: [{'a': 2, 'c': 1, 'b': 3},
     {'a': 2, 'c': 9, 'b': 7}],
 3: [{'a': 3, 'c': 2, 'b': 8}]}
Run Code Online (Sandbox Code Playgroud)

如果项目没有按排序顺序排列,那么您可以对它们进行排序然后使用,groupby或者您可以使用collections.OrderedDict(如果订单很重要)或collections.defaultdict在O(N)时间内执行此操作:

>>> from collections import OrderedDict
>>> d = OrderedDict()
>>> for item in items:
...     d.setdefault(item['a'], []).append(item)
...     
>>> dict(d.items())
{1: [{'a': 1, 'c': 8, 'b': 9},
     {'a': 1, 'c': 4, 'b': 5}],
 2: [{'a': 2, 'c': 1, 'b': 3},
     {'a': 2, 'c': 9, 'b': 7}],
 3: [{'a': 3, 'c': 2, 'b': 8}]}
Run Code Online (Sandbox Code Playgroud)

更新:

我看到你只想要返回那些我们没有用于分组的键,因为你需要做这样的事情:

>>> group_keys = {'a'}
>>> {k:[{k:d[k] for k in d.viewkeys() - group_keys} for d in g]
                                   for k, g in groupby(items, itemgetter(*group_keys))}
{1: [{'c': 8, 'b': 9},
     {'c': 4, 'b': 5}],
 2: [{'c': 1, 'b': 3},
     {'c': 9, 'b': 7}],
 3: [{'c': 2, 'b': 8}]}
Run Code Online (Sandbox Code Playgroud)


the*_*eye 5

注意:此代码假定数据已经排序.如果不是,我们必须手动排序

from itertools import groupby
print {key:list(grp) for key, grp in groupby(items, key=lambda x:x["a"])}
Run Code Online (Sandbox Code Playgroud)

产量

{1: [{'a': 1, 'b': 9, 'c': 8}, {'a': 1, 'b': 5, 'c': 4}],
 2: [{'a': 2, 'b': 3, 'c': 1}, {'a': 2, 'b': 7, 'c': 9}],
 3: [{'a': 3, 'b': 8, 'c': 2}]}
Run Code Online (Sandbox Code Playgroud)

要获得与您要求的格式相同的结果,

from itertools import groupby
from operator import itemgetter
a_getter, getter, keys = itemgetter("a"), itemgetter("b", "c"), ("b", "c")

def recon_dicts(items):
    return dict(zip(keys, getter(items)))

{key: map(recon_dicts, grp) for key, grp in groupby(items, key=a_getter)}
Run Code Online (Sandbox Code Playgroud)

产量

{1: [{'c': 8, 'b': 9}, {'c': 4, 'b': 5}],
 2: [{'c': 1, 'b': 3}, {'c': 9, 'b': 7}],
 3: [{'c': 2, 'b': 8}]}
Run Code Online (Sandbox Code Playgroud)

如果数据sorted尚未存在,您可以使用此答案中defaultdict方法,也可以使用函数进行排序,如下所示sorteda

{key: map(recon_dicts, grp)
   for key, grp in groupby(sorted(items, key=a_getter), key=a_getter)}
Run Code Online (Sandbox Code Playgroud)

参考文献:

  1. operator.itemgetter

  2. itertools.groupby

  3. zip,map,dict,sorted