Ответ 1
Подход defaultdict
, вероятно, лучше, если предположить, что c.Y
hashable, но здесь другой способ:
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, тем не менее это работает, тогда как подходdefaultdict
будет вызыватьTypeError
.Но будьте осторожны - в последних Pythons он поднимет
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
, которая делает эти два вместе. -
sblom answer работает для атрибутов hashable
c.Y
, с минимальным дополнительным пространством (потому что он вычисляет суммы напрямую). -
philhag answer в основном совпадает с sblom, но использует дополнительную вспомогательную память, создавая список каждого из
c
- эффективно делая то, чтоgroupby
, но с хешированием вместо предположения, что он отсортирован и с фактическими списками вместо итераторов.
Итак, если вы знаете, что ваш атрибут c.Y
hashable и нужны только суммы, используйте sblom's; если вы знаете, что это hashable, но хотите, чтобы они были сгруппированы для чего-то еще, используйте philhag's; если они не могут быть хешируемыми, используйте это (с дополнительным беспокойством, как отмечено, если они могут быть сложными или настраиваемый тип, который переопределяет __lt__
).