【问题标题】:Python: Writing Nested Dictionary to CSVPython:将嵌套字典写入 CSV
【发布时间】:2015-06-06 16:20:26
【问题描述】:

我正在尝试将嵌套字典写入 .csv 文件。这是一个简单的例子:

import csv
import itertools

fields = [ 'org', '2015', '2014', '2013' ]
dw     = { 'orgname1': { '2015' : 2, '2014' : 1, '2013' : 1 },
           'orgname2': { '2015' : 1, '2014' : 2, '2013' : 3 },
           'orgname3': { '2015' : 1, '2014' : 3, '2013' : 1 }
        }

with open("test_output.csv", "wb") as f:
    w = csv.writer( f )
    years = dw.values()[0].keys()
    for key in dw.keys():
        w.writerow([key, [dw[key][year] for year in years]])

这给我一个包含两列的表:第一列包含orgname;第二个包含 [2, 1, 1] (或子字典中的相应值)。我想要一个有四列的表格:一列用于orgname,然后三列用于对应的列表元素。

【问题讨论】:

  • dicts 没有顺序,所以你马上就有麻烦了
  • @PadraicCunningham 同意了。然而,他的钥匙似乎是按照字典顺序排列的。因此,他仍然可以通过对 dw.keys() 进行排序然后对其进行迭代来使其工作。

标签: python csv dictionary


【解决方案1】:

我认为这可能是一种更简单的方法:

import csv

fields = [ 'org', '2015', '2014', '2013' ]
dw     = { 'orgname1': { '2015' : 2, '2014' : 1, '2013' : 1 },
           'orgname2': { '2015' : 1, '2014' : 2, '2013' : 3 },
           'orgname3': { '2015' : 1, '2014' : 3, '2013' : 1 }
        }

with open("test_output.csv", "w") as csv_file:
  csvwriter = csv.writer(csv_file)
  csvwriter.writerow(['org', '2015', '2014', '2013'])

  for org in dw:
     csvwriter.writerow(org, dw[org]['2015'], dw[org]['2014'], dw[org]['2013'])

【讨论】:

  • 在最后一行中缺少括号以使其工作
【解决方案2】:

使用 DictWriter 无需预先对字段进行排序,因为w.writerow() 将确保正确的顺序。但是对项目本身进行排序确实很有意义。

所以综合以上所有建议并从中挑选出最好的,我会想出以下代码:

import csv
import itertools

def mergedict(a,b):
    a.update(b)
    return a

fields = [ 'org', '2015', '2014', '2013' ]
dw     = { 'orgname1': { '2015' : 2, '2014' : 1, '2013' : 1 },
           'orgname2': { '2015' : 1, '2014' : 2, '2013' : 3 },
           'orgname3': { '2015' : 1, '2014' : 3, '2013' : 1 }
        }

with open("test_output.csv", "wb") as f:
    w = csv.DictWriter( f, fields )
    w.writeheader()
    for k,d in sorted(dw.items()):
        w.writerow(mergedict({'org': k},d))

我添加了一个很小的 ​​mergedict() 函数,使其成为更下方的单线。

【讨论】:

    【解决方案3】:

    使用DictWriter 和标头的替代实现

    import csv
    import itertools
    
    fields = [ 'org', '2015', '2014', '2013' ]
    dw     = { 'orgname1': { '2015' : 2, '2014' : 1, '2013' : 1 },
               'orgname2': { '2015' : 1, '2014' : 2, '2013' : 3 },
               'orgname3': { '2015' : 1, '2014' : 3, '2013' : 1 }
            }
    
    with open("test_output.csv", "wb") as f:
        w = csv.DictWriter(f, fields)
        w.writeheader()
        for k in dw:
            w.writerow({field: dw[k].get(field) or k for field in fields})
    

    输出:

    org,2015,2014,2013
    orgname1,2,1,1
    orgname3,1,3,1
    orgname2,1,2,3
    

    【讨论】:

    • 我最喜欢您的回答,直截了当:) 您可以考虑按其键对dw 进行排序,因为在您的输出中,组织名称的顺序已从输入中改变。使用sorted(dw.items()) 解决了这个问题
    • 亲爱的 Python 3 用户,他们不想像我刚才所做的那样让自己感到尴尬,因为您只需将 open("test_output.csv", "wb") 切换为 open("test_output.csv", "w", newline=''),上述解决方案就可以了完美无缺。否则你会得到一个a bytes-like object is required, not 'str' when writing to a file' 。不要像我一样尝试将整个字典编码为ascii
    • 如果我的任何键的值为 0,那么如果 2015:0 用于 orgname1,我将键作为值,如 orgname1,orgname1,1,1。所以任何解决方案。 @Łukasz Rogalski
    【解决方案4】:

    这看起来像是DictWriter 的工作:

    import csv
    import itertools
    import sys
    
    fields = [ 'org', '2015', '2014', '2013' ]
    dw     = { 'orgname1': { '2015' : 2, '2014' : 1, '2013' : 1 },
               'orgname2': { '2015' : 1, '2014' : 2, '2013' : 3 },
               'orgname3': { '2015' : 1, '2014' : 3, '2013' : 1 }
            }
    
    w = csv.DictWriter( sys.stdout, fields )
    for key,val in sorted(dw.items()):
        row = {'org': key}
        row.update(val)
        w.writerow(row)
    

    【讨论】:

    • 实际上你应该得到最好的评论,因为你是第一个完整的解决方案,我喜欢你使用 dicts 更新功能的方式。我在一个单独的函数中对其进行了调整,以便之后将其保持为一个衬里。所以我的答案几乎是你的,改为文件输出并添加标题:)
    【解决方案5】:

    变化:

    w.writerow([key, [dw[key][year] for year in years]])
    

    收件人:

    w.writerow([key] + [dw[key][year] for year in years])
    

    否则,您尝试将 [orgname1, [2, 1, 1]] 之类的内容写入 csv,而您的意思是 [orgname1, 2, 1, 1]

    正如 Padraic 所说,您可能需要将 years = dw.values()[0].keys() 更改为 years = sorted(dw.values()[0].keys())years = fields[1:] 以避免随机行为。

    【讨论】:

    • 如果您按照其他答案中的建议使用 DictWriter,则无需对年份进行排序
    • @hexereisoftware 是的,但现在只是复制。
    猜你喜欢
    • 1970-01-01
    • 2016-12-12
    • 2018-10-27
    • 2021-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    相关资源
    最近更新 更多