3

这里的总 Python 菜鸟,可能缺少一些明显的东西。我到处搜索,还没有找到解决方案,所以我想我会寻求帮助。

我正在尝试编写一个函数,该函数将从一个大型 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,

ETC...

我需要的输出字典如下所示:

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 文件通常没有标题,但为了尝试获得此函数的工作版本,我手动插入了标题行。理想情况下,会有一些代码分配标题。

非常感谢任何帮助/方向/建议,谢谢!

4

2 回答 2

6
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这里使用了 a ,它就像一个字典,但是当您引用一个不存在的键而不是引发异常时,它只会创建一个默认值,在这种情况下是 a dict。然后我出去 - 并删除 -BrandProduct,并存储剩余部分。

我认为剩下的就是将成本和价格变成数字而不是字符串。

[修改为DictReader直接使用而不是reader]

于 2012-08-31T18:46:31.307 回答
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,这里第一级的键是Brandint 原始字典的值,所以我从原始 csv 文件中提取它为

dict_brand=new_dict.get(row['Brand'],dict())

这将判断我们的新dict中是否存在Brand与原始dict相同的值,如果是,它只是插入,如果不是,它创建,那么可能最复杂的部分是第二级或中间级,这里你设置原始dict的值Product作为key的新dict的Brand值,并且该值也是以原始dict为值Product的第三级dict的key,在这里我将它们提取为:PriceCost

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'}}}

就是这样。

于 2016-09-16T04:29:58.820 回答