Объединение объектов на основе определенных атрибутов и объединение (суммирование) определенных других атрибутов

1

Скажем, у меня есть 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>]
"""
  • 0
    Лично я не думаю, что переопределение оператора __eq__ является хорошей идеей, поскольку это означает, что отныне MyObject('A', 'B', 'C', 1) == MyObject('A', 'B', 'C', 1425)
  • 0
    @WillemVanOnsem по крайней мере, это __hash__ реализации __hash__ .
Показать ещё 1 комментарий
Теги:
python-3.x
merge

1 ответ

2
Лучший ответ

Я думаю, что неплохо "адаптировать" функции __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 вместе с новым количеством может также улучшить дизайн кода.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню