Как сохранить общую сумму вывода для каждого объекта категории?

#python #data-structures

#python #структуры данных

Вопрос:

У меня есть Category класс, и для каждого экземпляра этого класса есть атрибут ledger. Этот атрибут книги фактически представляет собой список словарей, которые содержат суммы вывода и депозита и описания в форме {"amount" : amount, "description" : description} . Теперь я хочу определить функцию create_spend_chart , которая будет принимать список объектов в качестве параметра и найдет общую сумму вывода. Я смог сделать это успешно:

     def create_spend_chart(categories):
        total_withdrawn = 0
        for i in categories:
            for p in i.ledger:
                if p["amount"] < 0:
                    total_withdrawn  = -p["amount"]
  

Но проблема, с которой я сталкиваюсь здесь, заключается в том, что я не могу сохранить общую сумму вывода для каждого объекта категории отдельно. Как я могу это сделать?

Моя кодовая база может помочь вам ответить на вопрос:

     class Category:
        def __init__(self, name):
            self.name = name
            self.ledger = list()
    
        def get_balance(self):
            total_balance = 0
            for i in self.ledger:
                total_balance  = i["amount"]
            return total_balance
    
        def check_funds(self, amount):
            if self.get_balance() >= amount:
                return True
            else:
                return False
        
        def deposit(self, amount, description = "Deposit"):
            form = {"amount" : int(amount), "description" : description}
            self.ledger.append(form)
        
        def withdraw(self, amount, description = "Withdrawal"):
            if description == None:
                description = "Withdrawal"
    
            form = {"amount" : -int(amount), "description" : description}
            if self.check_funds(amount):
                self.ledger.append(form)
                return True
            else:
                return False
        
        def transfer(self, amount, category_object):
            form1 = {"amount" : -int(amount), "description" :  f"Transfer to {category_object.name}"}
            form2 = {"amount" : int(amount), "description" :  f"Transfer from {self.name}"}
            
            if self.check_funds(amount):
                self.ledger.append(form1)
                category_object.ledger.append(form2)
                return True
            else:
                return False
        def __repr__(self):
            Ledger = ""
            for i in self.ledger:
                if len(i["description"]) > 23:
                    des = i["description"][:23]
                else:
                    des = i["description"]
                Ledger  = des.ljust(23)   str(round(i["amount"], 2)).rjust(7)   "n"
            Ledger = Ledger   "Total: "   str(round(self.get_balance(), 2))
            receipt = f"{self.name}".center(30, "*")   "n"   Ledger
            return receipt
    
    def create_spend_chart(categories):
        total_withdrawn = 0
        withdrawals = list()
        for i in categories:
            for p in i.ledger:
                if p["amount"] < 0:
                    total_withdrawn  = -p["amount"]
  

PS: Эта функция не является методом, она определяется вне объявления класса.

Ответ №1:

Используйте a collections.defaultdict , чтобы сделать такие агрегации простыми, как пирог.

 import collections

# ...

withdrawn_per_category = collections.defaultdict(int)
for i in categories:
    for p in i.ledger:
        if p["amount"] < 0:
            withdrawn_per_category[i.name]  = -p["amount"]
  

(Я решил использовать int в качестве типа данных по умолчанию, но здесь это не имеет большого значения, если это конвертируемый числовой тип.)

Без collections

Если по какой-то причине вы не хотите использовать удобный встроенный collections модуль, вы можете самостоятельно эмулировать то же поведение с помощью обычного dict:

 withdrawn_per_category = {}
for i in categories:
    for p in i.ledger:
        if p["amount"] < 0:
            withdrawn_per_category[i.name] = withdrawn_per_category.get(i.name, 0) - p["amount"]
  

Комментарии:

1. Спасибо за ответ!! Есть ли какой-либо способ, которым я мог бы сохранить эти значения (снятие средств для каждой категории) в списке вместо словаря?

2. Конечно. Самым простым способом было бы сделать что-то вроде withdrawals_per_category_list = list(withdrawn_per_category.items()) после того, как вы это сделали.

3. К сожалению, я столкнулся с проблемой. Когда я сейчас запускаю программу, она выдает ошибку NameError: name 'collections' is not defined . Что мне с этим делать?

4. Добавить import collections .

5. Да, есть, но зачем беспокоиться? collections это встроенный модуль, он доступен с каждым Python. (Тем не менее, я добавил версию dict без коллекций.)