【问题标题】:Assign many values to one key value - Python For Loop为一个键值分配多个值 - Python For Loop
【发布时间】:2021-04-18 22:45:17
【问题描述】:

我正在与客户一起练习使用数据集。每个客户都有名字、姓氏、城市、年龄、性别和发票号码。

我想创建一个字典,其中客户的名字和姓氏作为键值,并将其余信息附加到键值中。每个客户可以有多个发票,因此客户应该只计算一次并且有多个发票编号。

City    FirstName   LastName    Gender  Age InvoiceNum
NYC Jane    Doe Female  35  1023
NYC Jane    Doe Female  35  6523
Jersey City John    Smith   Male    54  6985
Houston Kay Johnson Female  45  2357

为此,我想创建一个 for 循环。

class Customers:
   city = ""
   age = 0
   invoices = []

f = open("customers".csv)
import csv
reader = csv.reader (f)
next(reader)

customers = {}
for row in reader:

这就是我卡住的地方。对于阅读器中的每一行,我想检查客户是否已经存在。如果存在,我想添加重复的发票编号。如果不存在,这将是一个新客户,我必须在其中附加其他值(城市、性别、年龄、单一发票编号)。

所需的输出:

有 3 个客户。 2个女性,1个男性。他们的平均年龄是 xxxx。

客户数量不会重复 Jane Doe。 Jane Doe 的女性计数不再重复。平均年龄不会是 Jane Doe 年龄的两倍。

【问题讨论】:

  • 阅读 csv 的方法如下:docs.python.org/3/library/csv.html。如果你想知道一个键是否已经在字典中,你可以简单地使用 your_key in customers 它将返回一个布尔值
  • 这不能解决将多个发票附加到唯一名称的问题。我在使用 for 循环时遇到问题。
  • 欢迎来到 SO!请显示您的数据集和预期结果结构。您的代码在 class Customers.csv 不是字符串上的属性之后缺少冒号。我建议显示minimal reproducible example 以消除猜测。谢谢。
  • “.csv”文件的内容也会很有帮助。
  • 谢谢!我很高兴能更多地了解python。我添加了 csv 样本。不确定如何正确格式化 - 随意编辑

标签: python dictionary for-loop


【解决方案1】:

我想出了这个:

from collections import defaultdict
from dataclasses import dataclass, field
from typing import List

@dataclass
class Customer:
    first_name: str = ''
    last_name: str = ''
    city: str = ''
    age: int = 0
    invoices: List = field(init=False, default_factory=list)
    
    def process_entry(self, **row):
        self.first_name = row['FirstName']
        self.last_name = row['LastName']
        self.city = row['City']
        self.age = row['Age']
        self.invoices.append(row['InvoiceNum'])

fake_reader = [
    {
        'FirstName': 'John',
        'LastName': 'Doe',
        'City': 'New York',
        'Age': 30,
        'InvoiceNum': 1
    },
    {
        'FirstName': 'John',
        'LastName': 'Doe',
        'City': 'New York',
        'Age': 30,
        'InvoiceNum': 2
    },
    {
        'FirstName': 'Clark',
        'LastName': 'Kent',
        'City': 'Metropolis',
        'Age': 35,
        'InvoiceNum': 3
    }
]

customers = defaultdict(Customer)
for row in fake_reader:
    customers[(row['FirstName'], row['LastName'])].process_entry(**row)

print(customers)

输出:

defaultdict(<class '__main__.Customer'>, {('John', 'Doe'): Customer(first_name='John', last_name='Doe', city='New York', age=30, invoices=[1, 2]), ('Clark', 'Kent'): Customer(first_name='Clark', last_name='Kent', city='Metropolis', age=35, invoices=[3])})

这里的“技巧”是用默认值定义Customer 类,这样可以使用 process_entry 方法填充真实值。

【讨论】:

    【解决方案2】:

    我认为您正在寻找类似的东西:

    if name not in customers:
        customers[name] = [invoice]
    else: 
        customers[name].append(invoice)
    

    这将创建一个键值对,其值作为一个数组,然后可以在每次 for 循环找到该名称的新发票时附加到该数组。

    编辑:更新以匹配您的 csv 文件

    customers = {}
    # [1:] to ignore file header
    for row in reader[1:]:
       City, FirstName, LastName, Gender, Age, InvoiceNum = row.split().strip()
       newEntry = {'InvoiceNum': int(InvoiceNum), 'City': City, 'Gender': Gender, 'Age': int(Age)}
       
      if (FirstName, LastName) not in customers:
        customers[(FirstName, LastName)] = [newEntry]
      else: 
        customers[(FirstName, LastName)].append(newEntry)
    

    不可变类型可以是字典键,所以我选择了名字和姓氏的元组。

    编辑:我希望我的回答能带你走向正确的方向,我将“csv”详细信息留给了你,因为你的行可能与我在那里所做的不对应。

    【讨论】:

    • 这里的d是什么意思?
    • 我的错我的意思是customers。它代表字典。
    猜你喜欢
    • 2020-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多