在Python3中合并字典列表中相同键的值,并与另一个字典列表比较

0 投票
1 回答
999 浏览
提问于 2025-04-17 21:40

更新:显然,我注意到在我的主代码中,当我从readExpenses.py获取的字典列表中提取值时,我把它存储为一个集合,而不是字典列表。

现在,我知道我用以下代码将每个字典存储在'exp'列表中:

for e in expenses:

    exp.append(e)

不过,我只想要这些字典中的“金额”和“类型”这两个键,而不是其他的内容。

作为参考,这里是一个支出字典中的键列表:

"Date","Description","Type","Check Number","Amount","Balance"

正如之前提到的,我只需要“类型”和“金额”。

我正在尝试制作一个预算程序,所以我有这个字典列表:

[{'Bills': 30.0}, {'Bills': 101.53}, {'Bills': 60.0}, {'Bills': 52.45}, {'Gas': 51.17}, {500.0: 'Mortgage'}, {'Food': 5.1}]

我还想把它和这个字典列表进行比较:

[{400.0: 'Bills'}, {'Gas': 100.0}, {500.0: 'Mortgage'}, {'Food': 45.0}]

第一个列表是我在某个月花费在不同服务上的钱,以及它们属于哪个类别,第二个字典是预算允许我在该类别上花费的最大金额。

我的目标是,在第一个字典中,将相同键的所有值合并成一个键:值对,然后与第二个字典进行比较。

所以我应该从第一个字典中得到这个字典列表:

[{'Bills': 295.15), {'Gas': 51.17}, {500.0: 'Mortgage'}, {'Food': 5.1}]

我试着查看这个例子这个例子,但它们只是关于将字典列表合并在一起,而不是对相同键的值进行求和。我确实尝试了后者的代码,但它只是把字典连接在一起。我发现sum似乎只对“原始”字典有效,而不适用于字典列表。

我尝试了这个作为一个思考实验:

print(sum(item['amount'] for item in exp))

我知道这会对金额下的所有数字进行求和,而不是返回每个类别的数字,但我想试试看,看看是否能找到解决方案,但我得到了这个错误:

TypeError: 'set' object is not subscriptable

当我尝试时,Counter函数似乎也有可能是一个解决方案,但它似乎只适用于单独的字典,而不适用于字典列表。

#where exp is the first dictionary that I mentioned
a = Counter(exp)
b = Counter(exp) 

c = a + b #I'm aware the math would have be faulty on this, but this was a test run
print (c)

这个尝试返回了这个错误:

TypeError: unhashable type: 'set'

另外,有没有办法不导入collections模块,而是使用Python自带的功能来实现呢?

我的代码:

from readExpense import *
from budget import *
from collections import *

#Returns the expenses by expenses type
def expensesByType(expenses, budget):

    exp = []

    expByType = []

    bud = []


    for e in expenses:

        entry = {e['exptype'], e['amount']}

        exp.append(entry)

    for b in budget:
        entry = {b['exptype'], b['maxamnt']}

        bud.append(entry)



    return expByType;


def Main():

    budget = readBudget("budget.txt")
    #printBudget(budget)

    expenses = readExpenses("expenses.txt")
    #printExpenses(expenses)

    expByType = expensesByType(expenses, budget)        

if __name__ == '__main__':
    Main()

另外,以下是budget和readExpense的代码供参考。

budget.py

def readBudget(budgetFile):
    # Read the file into list lines
    f = open(budgetFile)
    lines = f.readlines()
    f.close()

    budget = []

    # Parse the lines
    for i in range(len(lines)):
        list = lines[i].split(",")

        exptype = list[0].strip('" \n')
        if exptype == "Type":
            continue

        maxamount = list[1].strip('$" \n\r')

        entry = {'exptype':exptype, 'maxamnt':float(maxamount)}

        budget.append(entry)

    return budget

def printBudget(budget):
    print()
    print("================= BUDGET ==================")
    print("Type".ljust(12), "Max Amount".ljust(12))

    total = 0
    for b in budget:
        print(b['exptype'].ljust(12), str("$%0.2f" %b['maxamnt']).ljust(50))
        total = total + b['maxamnt']

    print("Total: ", "$%0.2f" % total)

def Main():
    budget = readBudget("budget.txt")
    printBudget(budget)

if __name__ == '__main__':    
    Main()

readExpense.py

def readExpenses(file):

    #read file into list of lines
    #split lines into fields
    # for each list create a dictionary
    # add dictionary to expense list

    #return expenses in a list of dictionary with fields
    # date desc, exptype checknm, amnt

    f = open(file)
    lines=f.readlines()
    f.close()

    expenses = []

    for i in range(len(lines)):
        list = lines[i].split(",")

        date = list[0].strip('" \n')
        if date == "Date":
            continue

        description = list[1].strip('" \n\r')
        exptype= list[2].strip('" \n\r')
        checkNum = list[3].strip('" \n\r')
        amount = list[4].strip('($)" \n\r')
        balance = list[5].strip('" \n\r')

        entry  ={'date':date, 'description': description, 'exptype':exptype, 'checkNum':checkNum, 'amount':float(amount), 'balance': balance}

        expenses.append(entry)

    return expenses

def printExpenses(expenses):

    #print expenses
    print()
    print("================= Expenses ==================")
    print("Date".ljust(12), "Description".ljust(12), "Type".ljust(12),"Check Number".ljust(12), "Amount".ljust(12), "Balance".ljust(12))

    total = 0

    for e in expenses:
        print(str(e['date']).ljust(12), str(e['description']).ljust(12), str(e['exptype']).ljust(12), str(e['checkNum']).ljust(12), str(e['amount']).ljust(12))
        total = total + e['amount']


    print()

    print("Total: ", "$%0.2f" % total)

def Main():
    expenses = readExpenses("expenses.txt")
    printExpenses(expenses)

if __name__ == '__main__':
    Main()

1 个回答

0

你有没有想过为什么不创建一些对象来管理这个呢?如果是我,我会选择用对象来处理,像下面这样做(这段代码完全没有测试,可能有错字):

#!/usr/bin/env python3

from datetime import datetime # why python guys, do you make me write code like this??
from operator import itemgetter

class BudgetCategory(object):
    def __init__(self, name, allowance):
        super().__init__()
            self.name = name # string naming this category, e.g. 'Food'
            self.allowance = allowance # e.g. 400.00 this month for Food
            self.expenditures = [] # initially empty list of expenditures you've made

    def spend(self, amount, when=None, description=None):
        ''' Use this to add expenditures to your budget category'''
        timeOfExpenditure = datetime.utcnow() if when is None else when #optional argument for time of expenditure
        record = (amount, timeOfExpenditure, '' if description is None else description) # a named tuple would be better here...
        self.expenditures.append(record) # add to list of expenditures
        self.expenditures.sort(key=itemgetter(1)) # keep them sorted by date for the fun of it

    # Very tempting to the turn both of the following into @property decorated functions, but let's swallow only so much today, huh?
    def totalSpent(self):
        return sum(t[0] for t in self.expenditures)

    def balance(self):
        return self.allowance - self.totalSpent()

这样我就可以写出看起来像这样的代码:

budget = BudgetCategory(name='Food', allowance=200)
budget.spend(5)
budget.spend(8)

print('total spent:', budget.totalSpent())
print('left to go:', budget.balance())

这只是一个起点。接下来你可以添加一些方法,把支出列表按装饰品分类(比如“我上个月在Twinkies上花了多少钱???”)。你还可以添加一个方法,从文件中解析条目,或者把它们输出成csv列表。你可以根据时间做一些图表。

撰写回答