Python中按相同属性对对象列表进行分组和求和的最简洁方法是什么

2024-02-08

我有一个 C 类型的对象列表,其中 C 类型由属性 X、Y、Z 组成,例如 c.X、c.Y、c.Z

现在我想执行以下任务:

  • 对属性 Y 具有相同值的那些对象的属性 Z 进行求和
  • 输出元组列表(Y,与此 Y 的 Z 之和)

最简洁的方法是什么?


The defaultdict假设方法可能更好c.Y是可散列的,但还有另一种方法:

from itertools import groupby
from operator import attrgetter
get_y = attrgetter('Y')
tuples = [(y, sum(c.Z for c in cs_with_y) for y, cs_with_y in 
           groupby(sorted(cs, key=get_y), get_y)]

更具体地说明差异:

  • 这种方法需要制作一个排序副本cs,这需要 O(n log n) 时间和 O(n) 额外空间。或者,你可以这样做cs.sort(key=get_y)排序cs就地,不需要额外的空间,但会修改列表cs。注意groupby返回一个迭代器,因此没有任何额外的开销。如果c.Y价值观不是hashable http://docs.python.org/glossary.html不过,这确实有效,而defaultdict方法会抛出一个TypeError.

    但要小心——在最近的 Python 中它会引发TypeError如果其中有任何复数,也许在其他情况下。有可能通过适当的方法来实现这项工作key功能 -key=lambda e: (e.real, e.imag) if isinstance(e, complex) else e似乎对我现在尝试过的任何事情都有效,尽管当然自定义类会覆盖__lt__运算符提出异常仍然不行。也许您可以定义一个更复杂的关键函数来测试这一点,等等。

    当然,我们在这里关心的是相同的事物彼此相邻,而不是实际排序,如果您愿意,您可以编写一个 O(n^2) 函数来做到这一点,而不是排序。或者是 O(num_hashable + num_nonhashable^2) 的函数。或者你可以编写 O(n^2) / O(num_hashable + num_nonhashable^2) 版本groupby这两者结合在一起。

  • 斯布洛姆的回答 https://stackoverflow.com/a/9012923/344821适用于可哈希的c.Y属性,具有最小的额外空间(因为它直接计算总和)。

  • 菲尔哈格的回答 https://stackoverflow.com/a/9012895/344821与 sblom 基本相同,但通过列出每个的列表来使用更多的辅助内存cs——有效地做什么groupby确实如此,但是使用散列而不是假设它已排序并且使用实际列表而不是迭代器。

所以,如果你知道你的c.Y属性是可散列的,只需要总和,使用 sblom 的;如果您知道它是可散列的,但还希望将它们分组用于其他用途,请使用 philhag's;如果它们可能不可散列,请使用这个(如果它们可能很复杂或者是覆盖的自定义类型,请额外担心__lt__).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python中按相同属性对对象列表进行分组和求和的最简洁方法是什么 的相关文章

随机推荐