Python将CSV转换为字典

10

我对Python还比较陌生。我需要创建一个将csv数据加载到字典中的类。

我希望能够控制键和值,所以让我们看下面的代码,我可以随时提取worker1.name或worker1.age。

class ageName(object):
'''class to represent a person'''
def __init__(self, name, age):
self.name = name
self.age = age

worker1 = ageName('jon', 40)
worker2 = ageName('lise', 22)

#Now if we print this you see that it`s stored in a dictionary
print worker1.__dict__
print worker2.__dict__
#
'''
{'age': 40, 'name': 'jon'}
#
{'age': 22, 'name': 'lise'}
#
'''
#

#when we call (key)worker1.name we are getting the (value)
print worker1.name
#
'''
#
jon
#
'''

但是我卡在了将我的CSV数据加载到键和值中。

[1] 我想创建自己的键,例如:worker1 = ageName([name],[age],[id],[gender])

[2] 每个[name]、[age]、[id]和[gender]都来自于CSV数据文件中特定的某一列。

我真的不知道如何处理这个问题。我尝试了很多方法,但都失败了。我需要一些帮助来开始解决这个问题。

---- 编辑 这是我的原始代码:

import csv

# let us first make student an object

class Student():
    def __init__(self):
        self.fname = []
        self.lname = []
        self.ID = []
        self.sport = []
        # let us read this file
        for row in list(csv.reader(open("copy-john.csv", "rb")))[1:]:
            self.fname.append(row[0])
            self.lname.append(row[1])   
            self.ID.append(row[2])
            self.sport.append(row[3])
    def Tableformat(self):
        print "%-14s|%-10s|%-5s|%-11s" %('First Name','Last Name','ID','Favorite Sport')
        print "-" * 45
        for (i, fname) in enumerate(self.fname):
           print "%-14s|%-10s|%-5s|%3s" %(fname,self.lname[i],self.ID[i],self.sport[i])
    def Table(self):
        print self.lname

class Database(Student):
    def __init__(self):
        g = 0
        choice = ['Basketball','Football','Other','Baseball','Handball','Soccer','Volleyball','I do not like sport']
        data = student.sport
        k = len(student.fname)
        print k
        freq = {}
        for i in data:
            freq[i] = freq.get(i, 0) + 1
        for i in choice:
            if i not in freq:
                freq[i] = 0
            print i, freq[i]


student = Student()
database = Database()

这是我的当前代码(不完整)

import csv
class Student(object):
    '''class to represent a person'''
    def __init__(self, lname, fname, ID, sport):
        self.lname = lname
        self.fname = fname
        self.ID = ID
        self.sport = sport
reader = csv.reader(open('copy-john.csv'), delimiter=',', quotechar='"')
student = [Student(row[0], row[1], row[2], row[3]) for row in reader][1::]
print "%-14s|%-10s|%-5s|%-11s" %('First Name','Last Name','ID','Favorite Sport')
print "-" * 45
for i in range(len(student)):
    print "%-14s|%-10s|%-5s|%3s" %(student[i].lname,student[i].fname,student[i].ID,student[i].sport)

choice = ['Basketball','Football','Other','Baseball','Handball','Soccer','Volleyball','I do not like sport']
lst = []
h = 0
k = len(student)
# 23
for i in range(len(student)):
    lst.append(student[i].sport) # merge together

for a in set(lst):
    print a, lst.count(a)

for i in set(choice):
    if i not in set(lst):
        lst.append(i)
        lst.count(i) = 0
        print lst.count(i)

请注意,如果您真的想要一个字典,则无法使用 worker1.name 来获取这些值。必须使用 worker1['name']形式来访问字典。那么,您真正想要哪一个呢? - Peter Hansen
嗨,彼得。我很抱歉,也非常感谢你的评论。那是一个好问题。有什么利弊吗?我很抱歉... - CppLearner
总是有利弊,但你要求一个字典。你的意思是你不知道是否应该使用它吗?为了回答这个问题,我们需要更多地了解你打算用数据做什么。 - Peter Hansen
我怀疑只是因为所有实例数据都存储在属于该实例的字典中,所以存在一些混淆。 - Tor Valamo
我刚刚编辑了我的帖子。您可以查看我的原始代码和当前代码。我正在创建一个小程序,将“学生”作为对象,并具有诸如性别、姓名之类的属性。目前使用Tor Valamo的代码是处理某些内容的好方法。然而,当我转到其他任务时,发现自己不断重申for i in range循环,只是为了提取整个student.fnames、student.lnames、student.ID。 - CppLearner
我编辑了我的回答,向您展示了一些关于您的编辑的快捷方式。 - Tor Valamo
4个回答

12
import csv

reader = csv.reader(open('workers.csv', newline=''), delimiter=',', quotechar='"')
workers = [ageName(row[0], row[1]) for row in reader]

现在workers有所有工人的列表

>>> workers[0].name
'jon'

在问题修改后添加编辑内容

你使用旧式类(class)的原因是什么?我这里正在使用新式类。

class Student:
    sports = []
    def __init__(self, row):
       self.lname, self.fname, self.ID, self.sport = row
       self.sports.append(self.sport)
    def get(self):
       return (self.lname, self.fname, self.ID, self.sport)

reader = csv.reader(open('copy-john.csv'), delimiter=',', quotechar='"')
print "%-14s|%-10s|%-5s|%-11s" % tuple(reader.next()) # read header line from csv
print "-" * 45
students = list(map(Student, reader)) # read all remaining lines
for student in students:
    print "%-14s|%-10s|%-5s|%3s" % student.get()

# Printing all sports that are specified by students
for s in set(Student.sports): # class attribute
    print s, Student.sports.count(s)

# Printing sports that are not picked 
allsports = ['Basketball','Football','Other','Baseball','Handball','Soccer','Volleyball','I do not like sport']
for s in set(allsports) - set(Student.sports):
    print s, 0
希望这给你带来了一些关于Python序列的强大应用的想法。 ;)
编辑2,尽可能地缩短...只是为了炫耀:P
女士们先生们,7(.5)行。
allsports = ['Basketball','Football','Other','Baseball','Handball',
             'Soccer','Volleyball','I do not like sport']
sports = []
reader = csv.reader(open('copy-john.csv'))
for row in reader:
    if reader.line_num: sports.append(s[3])
    print "%-14s|%-10s|%-5s|%-11s" % tuple(s)
for s in allsports: print s, sports.count(s)

哇这太酷了。我是Python的新手,所以不知道什么是新式/旧式写法。我得在休息期间学习一下。你能再帮我一个忙吗?你的代码很棒,但会出现两个错误: Traceback (most recent call last): File "D:/Python26/test2.py", line 13, in <module> students = [Student(row) for row in reader] File "D:/Python26/test2.py", line 5, in init (self.lname,self.fname,self.ID,self.sport) = row ValueError: too many values to unpack - CppLearner
哦,实际上如果我添加 [1::] 回去,会出现以下错误: Traceback (most recent call last): File "D:/Python26/test2.py", line 13, in <module> students = [Student(row) for row in reader[1::]] TypeError: '_csv.reader' 对象不可切片。 - CppLearner
我更新了你问题附近的几行代码。请注意它读取标题行并首先将其打印出来,因此无需对读取器进行切片(你无法这样做,因为它是一个迭代器,这就是你收到错误的原因)。 - Tor Valamo
这段代码仍有改进的空间,我只是不确定这是否是你想要它实现的全部功能。如果是的话,我可以将其缩减约10行 :P - Tor Valamo
为什么不请你“关闭”文件呢?或者更好的方法是使用“with”? - Aprillion
显示剩余9条评论

9

我知道这是一个相当老的问题,但不看一下惊人的新(ish)Python库pandas就不可能。它的主要分析单元是一个称为DataFrame的东西,其模型是根据R处理数据的方式建立的。

假设你有一个(非常愚蠢的)名为example.csv的csv文件,它看起来像这样:

day,fruit,sales
Monday,Banana,10
Monday,Orange,20
Tuesday,Banana,12
Tuesday,Orange,22

如果您希望快速读取csv文件并执行相关操作,以下代码无论是简洁性还是易用性都是首选:
>>> import pandas as pd
>>> csv = pd.read_csv('example.csv')
>>> csv
       day   fruit  sales
0   Monday  Banana     10
1   Monday  Orange     20
2  Tuesday  Banana     12
3  Tuesday  Orange     22
>>> csv[csv.fruit=='Banana']
       day   fruit  sales
0   Monday  Banana     10
2  Tuesday  Banana     12
>>> csv[(csv.fruit=='Banana') & (csv.day=='Monday')]
      day   fruit  sales
0  Monday  Banana     10

在我看来,这真的是非常棒的东西。再也不用遍历csv.reader对象了!


1
很不错。谢谢。哦,之后呢?将近4年了! :) - CppLearner
这就是在线世界的疯狂之处:它永远不会死!我在完全正常的谷歌搜索中遇到了这个问题。希望你们尝试一下 pandas 并享受它! - LondonRob

8

我赞成Mark的建议。特别是,看一下csv模块中的DictReader,它允许将逗号分隔(或通用分隔符)的文件读取为字典。

请查看PyMotW对csv模块的覆盖,以快速参考和使用DictReader、DictWriter的示例。


我不理解为什么这被评为-1却没有解释性的评论。使用DictReader这个建议有什么问题吗? - CruiZen
我必须说,您发布的链接非常有用 =)。我会点赞支持您的。 (版主,我假设这可以吗?) - victorhooi

2

您是否看过csv模块?

import csv

是的,我做了。事实上,我有一个写得很糟糕的版本,但我意识到这很麻烦,所以我决定立即做字典。 - CppLearner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接