如何在Python中按相似索引/属性对元组/对象列表进行分组?

61 投票
4 回答
57956 浏览
提问于 2025-04-16 20:58

给定一个列表:

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 判断来实现,但这样看起来不太好。有没有更优雅的 Python 方法呢?顺便说一下,这些对象的属性都是字符串。

另外,如果能提供一个处理包含元组(长度相同)的列表的解决方案,那就更好了。

4 个回答

16

你可以试试使用 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
40

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

import itertools
import operator

你将会使用 itertools.groupbyoperator.attrgetter 或者 operator.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 在键的值变化时会创建一个新组。


你可以用这个方法创建一个像 S.Lott 的答案那样的 dict,但不一定要使用 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))
101

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()

撰写回答