首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python分组依据

Python分组依据
EN

Stack Overflow用户
提问于 2010-09-20 15:50:02
回答 6查看 192.5K关注 0票数 150

假设我有一组数据对,其中索引0是值,索引1是类型:

input = [
          ('11013331', 'KAT'), 
          ('9085267',  'NOT'), 
          ('5238761',  'ETH'), 
          ('5349618',  'ETH'), 
          ('11788544', 'NOT'), 
          ('962142',   'ETH'), 
          ('7795297',  'ETH'), 
          ('7341464',  'ETH'), 
          ('9843236',  'KAT'), 
          ('5594916',  'ETH'), 
          ('1550003',  'ETH')
        ]

我想按照它们的类型(通过第一个索引字符串)对它们进行分组,如下所示:

result = [ 
           { 
             type:'KAT', 
             items: ['11013331', '9843236'] 
           },
           {
             type:'NOT', 
             items: ['9085267', '11788544'] 
           },
           {
             type:'ETH', 
             items: ['5238761', '962142', '7795297', '7341464', '5594916', '1550003'] 
           }
         ] 

我如何才能以有效的方式实现这一点?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2010-09-20 15:54:41

分两步完成。首先,创建一个字典。

>>> input = [('11013331', 'KAT'), ('9085267', 'NOT'), ('5238761', 'ETH'), ('5349618', 'ETH'), ('11788544', 'NOT'), ('962142', 'ETH'), ('7795297', 'ETH'), ('7341464', 'ETH'), ('9843236', 'KAT'), ('5594916', 'ETH'), ('1550003', 'ETH')]
>>> from collections import defaultdict
>>> res = defaultdict(list)
>>> for v, k in input: res[k].append(v)
...

然后,将该字典转换为预期的格式。

>>> [{'type':k, 'items':v} for k,v in res.items()]
[{'items': ['9085267', '11788544'], 'type': 'NOT'}, {'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}, {'items': ['11013331', '9843236'], 'type': 'KAT'}]

使用itertools.groupby也是可能的,但它需要首先对输入进行排序。

>>> sorted_input = sorted(input, key=itemgetter(1))
>>> groups = groupby(sorted_input, key=itemgetter(1))
>>> [{'type':k, 'items':[x[0] for x in v]} for k, v in groups]
[{'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}, {'items': ['11013331', '9843236'], 'type': 'KAT'}, {'items': ['9085267', '11788544'], 'type': 'NOT'}]

请注意,这两种方法都不尊重键的原始顺序。如果您需要保持顺序,则需要一个OrderedDict。

>>> from collections import OrderedDict
>>> res = OrderedDict()
>>> for v, k in input:
...   if k in res: res[k].append(v)
...   else: res[k] = [v]
... 
>>> [{'type':k, 'items':v} for k,v in res.items()]
[{'items': ['11013331', '9843236'], 'type': 'KAT'}, {'items': ['9085267', '11788544'], 'type': 'NOT'}, {'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}]
票数 192
EN

Stack Overflow用户

发布于 2010-09-20 16:28:14

Python的内置itertools模块实际上有一个groupby函数,但是要分组的元素必须首先进行排序,以便要分组的元素在列表中是连续的:

from operator import itemgetter
sortkeyfn = itemgetter(1)
input = [('11013331', 'KAT'), ('9085267', 'NOT'), ('5238761', 'ETH'), 
 ('5349618', 'ETH'), ('11788544', 'NOT'), ('962142', 'ETH'), ('7795297', 'ETH'), 
 ('7341464', 'ETH'), ('9843236', 'KAT'), ('5594916', 'ETH'), ('1550003', 'ETH')] 
input.sort(key=sortkeyfn)

现在,输入如下所示:

[('5238761', 'ETH'), ('5349618', 'ETH'), ('962142', 'ETH'), ('7795297', 'ETH'),
 ('7341464', 'ETH'), ('5594916', 'ETH'), ('1550003', 'ETH'), ('11013331', 'KAT'),
 ('9843236', 'KAT'), ('9085267', 'NOT'), ('11788544', 'NOT')]

groupby返回形式为(key, values_iterator)的二元组序列。我们想要的是将其转换为一个字典列表,其中'type‘是键,'items’是由values_iterator返回的元组的第0个元素的列表。如下所示:

from itertools import groupby
result = []
for key,valuesiter in groupby(input, key=sortkeyfn):
    result.append(dict(type=key, items=list(v[0] for v in valuesiter)))

现在,result包含了您想要的字典,如您的问题所述。

不过,您可能会考虑只对此做一个字典,按类型键控,每个值都包含值列表。在您当前的表单中,要查找特定类型的值,必须遍历列表以找到包含匹配' type‘键的字典,然后从中获取’item‘元素。如果您使用单个字典而不是一列包含1个条目的字典,则可以通过在主字典中进行单键查找来查找特定类型的条目。使用groupby,这将如下所示:

result = {}
for key,valuesiter in groupby(input, key=sortkeyfn):
    result[key] = list(v[0] for v in valuesiter)

result现在包含这个字典(这类似于@KennyTM答案中的中间res默认字典):

{'NOT': ['9085267', '11788544'], 
 'ETH': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 
 'KAT': ['11013331', '9843236']}

(如果您想将其简化为一行程序,您可以:

result = dict((key,list(v[0] for v in valuesiter)
              for key,valuesiter in groupby(input, key=sortkeyfn))

或者使用新奇的字典-理解形式:

result = {key:list(v[0] for v in valuesiter)
              for key,valuesiter in groupby(input, key=sortkeyfn)}
票数 62
EN

Stack Overflow用户

发布于 2020-02-18 22:01:02

这个答案类似于@PaulMcG's answer,但不需要对输入进行排序。

对于那些函数式编程的人,groupBy可以在一行中编写(不包括导入!),而且与itertools.groupby不同的是,它不需要对输入进行排序:

from functools import reduce # import needed for python3; builtin in python2
from collections import defaultdict

def groupBy(key, seq):
 return reduce(lambda grp, val: grp[key(val)].append(val) or grp, seq, defaultdict(list))

(在lambda中使用... or grp的原因是,为了让这个reduce()工作,lambda需要返回它的第一个参数;因为list.append()总是返回None,所以or总是返回grp

这将返回一个dict,它的键是通过计算给定的函数找到的,其值是按原始顺序排列的原始项的列表。对于OP的示例,将其作为groupBy(lambda pair: pair[1], input)调用将返回以下dict:

{'KAT': [('11013331', 'KAT'), ('9843236', 'KAT')],
 'NOT': [('9085267', 'NOT'), ('11788544', 'NOT')],
 'ETH': [('5238761', 'ETH'), ('5349618', 'ETH'), ('962142', 'ETH'), ('7795297', 'ETH'), ('7341464', 'ETH'), ('5594916', 'ETH'), ('1550003', 'ETH')]}

这样就可以了:

result = {key: [pair[0] for pair in values],
          for key, values in groupBy(lambda pair: pair[1], input).items()}
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3749512

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档