【问题标题】:How to group a list of tuples/objects by similar index/attribute in python?如何在python中通过类似的索引/属性对元组/对象列表进行分组?
【发布时间】:2011-09-29 22:31:25
【问题描述】:

给定一个列表

old_list = [obj_1, obj_2, obj_3, ...]

我想创建一个列表:

new_list = [[obj_1, obj_2], [obj_3], ...]

obj_1.some_attr == obj_2.some_attr.

我可以同时抛出一些for 循环和if 检查,但这很难看。有没有一种pythonic方式?顺便说一句,对象的属性都是字符串。

也可以选择包含元组(相同长度)而不是对象的列表的解决方案。

【问题讨论】:

  • " 包含元组(相同长度)而不是对象的列表" 这是否意味着包含所有相同长度的元组的列表 ?如果是,元组分组的“属性”是什么? - 顺便说一句,元组是对象,不是吗?
  • @eyquem:1。是的; 2. 元组在某个索引处分组。索引处的项目是一个字符串。 3. 我相信是这样,……但我不确定。 :-)

标签: python list grouping


【解决方案1】:

defaultdict 是这样做的。

虽然for 循环在很大程度上是必不可少的,但if 语句则不是。

from collections import defaultdict


groups = defaultdict(list)

for obj in old_list:
    groups[obj.some_attr].append(obj)

new_list = groups.values()

【讨论】:

  • 这当然不会保留(或以任何方式尊重)组的原始顺序。所以它可能是也可能不是@Druss 想要的。
  • @jollybox.de:“不保留(或以任何方式尊重)组的原始顺序”正确。什么时候成为要求?
  • 我不知道这是否是一个要求,最初的问题并不清楚。我最初是这样阅读问题的。不过,很好的答案。
  • 刚刚意识到,如果您将dict 的用法与itertools.groupby 答案结合使用,您甚至不需要使用defaultdict
  • 不应该调用list(groups.values()) 来实际返回OP 想要的吗?我的意思是,否则,如果有人打电话给new_list[0],她会得到TypeError: 'dict_values' object does not support indexing(至少在我的机器上)。
【解决方案2】:

这里有两种情况。两者都需要以下导入:

import itertools
import operator

您将使用itertools.groupbyoperator.attrgetteroperator.itemgetter

对于您按obj_1.some_attr == obj_2.some_attr 分组的情况:

get_attr = operator.attrgetter('some_attr')
new_list = [list(g) for k, g in itertools.groupby(sorted(old_list, key=get_attr), get_attr)]

对于a[some_index] == b[some_index]

get_item = operator.itemgetter(some_index)
new_list = [list(g) for k, g in itertools.groupby(sorted(old_list, key=get_item), get_item)]

请注意,您需要排序,因为itertools.groupby 在键值更改时会创建一个新组。


请注意,您可以使用它来创建 dict,就像 S.Lott 的答案一样,但不必使用 collections.defaultdict

使用字典理解(仅适用于 Python 3+,可能还有 Python 2.7,但我不确定):

groupdict = {k: g for k, g in itertools.groupby(sorted_list, keyfunction)}

对于以前版本的 Python,或者作为更简洁的替代方案:

groupdict = dict(itertools.groupby(sorted_list, keyfunction))

【讨论】:

    【解决方案3】:

    认为您也可以尝试使用itertools.groupby。请注意,下面的代码只是一个示例,应根据您的需要进行修改:

    data = [[1,2,3],[3,2,3],[1,1,1],[7,8,9],[7,7,9]]
    
    from itertools import groupby
    
    # for example if you need to get data grouped by each third element you can use the following code
    res = [list(v) for l,v in groupby(sorted(data, key=lambda x:x[2]), lambda x: x[2])]# use third element for grouping
    

    【讨论】:

    • 基本上是我的答案,但你忘记了一个重要方面:在使用groupby之前进行排序。
    • @JAB - 你的真相。谢谢你注意到我。
    • @JAB - 为什么在使用 groupby 之前需要排序?
    • @SahilChhabra 阅读我的回答,我说原因。
    猜你喜欢
    • 1970-01-01
    • 2022-01-21
    • 2016-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-11
    相关资源
    最近更新 更多