Скажем, у меня есть MyObject
с атрибутами attr_a
, attr_b
и attr_c
и quantity.
Я хотел бы объединить их количества, если они имеют одинаковые attr_a
, attr_b
и attr_c
Вот пример и мой подход. Есть лучший способ сделать это? Например; что, если я захочу сохранить упорядочение своих списков после их объединения?
class MyObject:
def __init__(self, attr_a, attr_b, attr_c, quantity):
self.attr_a = attr_a
self.attr_b = attr_b
self.attr_c = attr_c
self.quantity = quantity
def __eq__(self, rhs):
if type(rhs) is type(self):
return self.attr_a == rhs.attr_a and self.attr_b == rhs.attr_b and self.attr_c == rhs.attr_c
else:
return False
def __hash__(self):
return hash((self.attr_a, self.attr_b, self.attr_c))
def __repr__(self):
return "<{}, {}, {}, {}>".format(self.attr_a, self.attr_b, self.attr_c, self.quantity)
from collections import defaultdict
pos1 = [MyObject("AAA", "BBB", "A123", 1000), MyObject("AAA", "CCC", "A123", 2000)]
pos2 = [MyObject("AAA", "BBB", "A123", 2000), MyObject("AAA", "CCC", "A123", -2000), MyObject("AAA", "DDD", "A999", 200)]
merge = defaultdict(int)
for p in pos1 + pos2:
merge[p] += p.quantity
res = []
for k, v in merge.items():
k.quantity = v
res.append(k)
print(res)
"""
Expected output: [<AAA, BBB, A123, 3000>, <AAA, CCC, A123, 0>, <AAA, DDD, A999, 200>]
"""
Я думаю, что неплохо "адаптировать" функции __eq__
и т.д. К конкретному __eq__
использования: прямо сейчас это означает, что MyObject("AAA", "BBB", "A123", 1000)
считается равным MyObject("AAA", "BBB", "A123", 1425)
. Для того, чтобы "объединить" такие объекты вместе, это может сработать, но это означает, что другие (простые) операции могут привести к множеству дополнительной логики.
Еще одна вещь, которую я бы избегал, - это изменение количества существующего MyObject
в целом: вы не знаете, какие переменные указывают на этот объект. В результате это может означать, что список, содержащий MyObject
, внезапно имеет список, в котором quantities
разные.
Возможно, лучше реализовать такую функцию, как get_key
:
class MyObject:
def __init__(self, attr_a, attr_b, attr_c, quantity):
self.attr_a = attr_a
self.attr_b = attr_b
self.attr_c = attr_c
self.quantity = quantity
def get_key(self):
return (self.attr_a, self.attr_b, self.attr_c)
def __repr__(self):
return "<{}, {}, {}, {}>".format(self.attr_a, self.attr_b, self.attr_c, self.quantity)
Затем мы выполняем более или менее похожий алгоритм, но мы строим новый MyObject
s:
from collections import defaultdict
res = defaultdict(int)
for obj in objs:
res[obj.get_key()] += obj.quantity
result = [MyObject(*k, v) for k, v in res.items()]
Создание некоторой функции clone
для копирования MyObject
вместе с новым количеством может также улучшить дизайн кода.
__eq__
является хорошей идеей, поскольку это означает, что отнынеMyObject('A', 'B', 'C', 1) == MyObject('A', 'B', 'C', 1425)
__hash__
реализации__hash__
.