我有一个 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 基本相同,但通过列出每个的列表来使用更多的辅助内存c
s——有效地做什么groupby
确实如此,但是使用散列而不是假设它已排序并且使用实际列表而不是迭代器。
所以,如果你知道你的c.Y
属性是可散列的,只需要总和,使用 sblom 的;如果您知道它是可散列的,但还希望将它们分组用于其他用途,请使用 philhag's;如果它们可能不可散列,请使用这个(如果它们可能很复杂或者是覆盖的自定义类型,请额外担心__lt__
).
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)