这里的总Python noob,可能遗漏了一些明显的东西。我到处搜索,还没有找到解决方案,所以我想我会请求一些帮助。
我正在尝试编写一个从大型csv文件构建嵌套字典的函数。输入文件采用以下格式:
Product,Price,Cost,Brand,
blue widget,5,4,sony,
red widget,6,5,sony,
green widget,7,5,microsoft,
purple widget,7,6,microsoft,
等...
我需要的输出字典如下:
projects = { `<Brand>`: { `<Product>`: { 'Price': `<Price>`, 'Cost': `<Cost>` },},}
但很明显,许多不同的品牌都含有不同的产品。在输入文件中,数据按品牌名称按字母顺序排序,但我知道一旦DictReader执行它就会变得无序,所以我肯定需要一种更好的方法来处理重复项。写入的if语句是多余的,不必要。
这是我到目前为止无法使用的无用代码:
def build_dict(source_file):
projects = {}
headers = ['Product', 'Price', 'Cost', 'Brand']
reader = csv.DictReader(open(source_file), fieldnames = headers, dialect = 'excel')
current_brand = 'None'
for row in reader:
if Brand != current_brand:
current_brand = Brand
projects[Brand] = {Product: {'Price': Price, 'Cost': Cost}}
return projects
source_file = 'merged.csv'
print build_dict(source_file)
我当然在文件顶部导入了csv模块。
最好的方法是什么?我觉得我已经离开了,但是关于从CSV创建嵌套dicts的信息很少,而且那里的例子非常具体,并且往往不详细解释为什么解决方案实际工作,所以作为Python的新手,有点难以得出结论。
此外,输入csv文件通常没有标题,但为了尝试获取此函数的工作版本,我手动插入标题行。理想情况下,会有一些代码分配标题。
非常感谢任何帮助/指导/推荐!谢谢!
答案 0 :(得分:4)
import csv
from collections import defaultdict
def build_dict(source_file):
projects = defaultdict(dict)
headers = ['Product', 'Price', 'Cost', 'Brand']
with open(source_file, 'rb') as fp:
reader = csv.DictReader(fp, fieldnames=headers, dialect='excel',
skipinitialspace=True)
for rowdict in reader:
if None in rowdict:
del rowdict[None]
brand = rowdict.pop("Brand")
product = rowdict.pop("Product")
projects[brand][product] = rowdict
return dict(projects)
source_file = 'merged.csv'
print build_dict(source_file)
产生
{'microsoft': {'green widget': {'Cost': '5', 'Price': '7'},
'purple widget': {'Cost': '6', 'Price': '7'}},
'sony': {'blue widget': {'Cost': '4', 'Price': '5'},
'red widget': {'Cost': '5', 'Price': '6'}}}
来自您的输入数据(其中merged.csv
没有标题,只有数据。)
我在这里使用了defaultdict
,这就像字典一样,但是当你引用一个不存在而不是引发异常的键时,它只会产生一个默认值,在这种情况下为{{1 }}。然后我离开 - 并删除 - dict
和Brand
,然后存储剩余部分。
我认为剩下的就是将成本和价格转换为数字而不是字符串。
[已修改为直接使用Product
而不是DictReader
]
答案 1 :(得分:0)
我在这里提供另一种满足您需求的方式(与DSM不同) 首先,这是我的代码:
import csv
new_dict={}
with open('merged.csv','rb')as csv_file:
data=csv.DictReader(csv_file,delimiter=",")
for row in data:
dict_brand=new_dict.get(row['Brand'],dict())
dict_brand[row['Product']]={k:row[k] for k in ('Cost','Price')}
new_dict[row['Brand']]=dict_brand
print new_dict
简而言之,要解决的要点是弄清楚键值对在您的要求中是什么。根据你的要求,它可以被称为 3-level-dict ,这里第一级的键是原始字典中Brand
int的值,所以我从中提取它原始csv文件为
dict_brand=new_dict.get(row['Brand'],dict())
将判断是否存在与我们的新词典中的原始词典相同的Brand
值,如果是,它只是插入,如果不是,它创建,那么也许最复杂的部分是第二个级别或中级,在这里您将原始字典的Product
的值设置为键Brand
的新字典的值,Product
的值也是该字符串的关键字。将原始字典的Price
和Cost
作为值的第三级字典,在这里我将其提取为:
dict_brand[row['Product']]={k:row[k] for k in ('Cost','Price')}
最后,我们需要做的就是将创建的'中间字典'设置为新字典的值,其中Brand
为关键字。
最后,输出是
{'sony': {'blue widget': {'Price': '5', 'Cost': '4'},
'red widget': {'Price': '6', 'Cost': '5'}},
'microsoft': {'purple widget': {'Price': '7', 'Cost': '6'},
'green widget': {'Price': '7', 'Cost': '5'}}}
就是这样。