【问题标题】:Using Python CSV DictReader to create multi-level nested dictionary使用 Python CSV DictReader 创建多级嵌套字典
【发布时间】:2012-08-26 14:14:27
【问题描述】:

这里的总 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,

等等……

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

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

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

【问题讨论】:

  • 你有两个独立的问题:第一个是解析,第二个是把数据放入字典。我建议您先不使用 csv.DictReader 来执行此操作 - 它只是令人困惑,并且使用本机拆分功能很容易实现。接下来 - 您应该附加到字典,而不是覆盖它(当您获得现有品牌的另一个项目时)。
  • 我同意@GuyAdini,你甚至不需要使用 csv 阅读器。只需手动操作,它也会为您提供更多选择。
  • 使用split 代替csv 非常诱人,但只有在您知道(例如)Product 绝不是“SuperUltraWidget,加拿大版”的情况下才会起作用。在所有条件相同的情况下,我认为现在学习使用csv 模块会更安全。
  • 即使使用 csv 库,您也必须编写代码来捕获 None 并找出解决方法。
  • @GuyAdini - 感谢您的建议。为了确保我理解正确,您认为最好打开文件,遍历 (',') 上的每一行拆分,并根据索引更新字典?感谢您抽出宝贵时间提供帮助。

标签: python python-2.7 csv dictionary


【解决方案1】:
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,它就像一个字典,但是当您引用一个不存在的键而不是引发异常时,它只会创建一个默认值,在本例中为dict。然后我退出 -- 并移除 -- BrandProduct,并存储剩余部分。

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

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

【讨论】:

  • 感谢帝斯曼,这真的很有帮助。但是,我实际上在每个 Product 值字典中都得到了 None: [''] 。由于我不熟悉 defaultdict,我不确定是什么原因造成的。这绝对比我所拥有的更接近解决方案,所以谢谢。
  • A defaultdict 只是一个字典,如果找不到密钥,它会生成一个并给它指定的值(在这种情况下,一个空字典)。你能举一个似乎生成无的数据线的例子吗?可能我只是错过了一些明显的事情,我知道这样做。 :-/
  • 当然,对于每个包含价格和成本的字典,它还创建了第三个键:无值对。因此,对于每个产品,它都会返回:{None: [''], 'Price': '27', 'Cost': '17'}
  • 嗯,令人费解:我根本没看到。您的merged.csv 与您提供的格式完全一致吗?末尾没有多余的逗号之类的吗?
  • 我只是在发表评论......似乎编辑我的问题的人删除了我声明添加空格是为了便于阅读的句子。我刚刚编辑了主要问题以反映确切的格式。很抱歉造成混乱,我刚刚注意到我的原件已被编辑。
【解决方案2】:

在这里我提供另一种方式来满足您的要求(不同于 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())

这将判断我们的新dict中是否存在与原始dict相同的Brand值,如果是,它只是插入,如果不是,它创建,那么最复杂的部分可能是第二级或中层,这里将原dict的Product的值设置为keyBrand的新dict的值,Product的值也是第三级dict的key,有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'}}}

就是这样。

【讨论】:

    猜你喜欢
    • 2021-03-04
    • 1970-01-01
    • 2022-01-25
    • 2021-02-20
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    相关资源
    最近更新 更多