如何将嵌套字典的内容以某种格式写入文件



我有一个字典的字典,我试图以某种方式输出其中的信息,以便它将用于下游分析。注意:dict中的所有键也在list中。

for item in list:
    for key, value in dict[item].items():
        print item, key, value

这是我最接近我想要的了,但还有很长的路要走。理想情况下我想要的是:

     item1  item2  item3  item4
key1 value  value  value  value
key2 value  value  value  value
key2 value  value  value  value

这可能吗?

首先,如果我理解您的结构,列表只是对外部字典的键进行排序的一种方式,并且您的许多复杂性都是试图将这两者一起使用以模拟有序字典。如果是这样,有一个更简单的方法:使用collections.OrderedDict。我将在最后回到这个问题。


首先,需要获得子字典的所有键,因为这些是输出的行。

从注释中,听起来dct中的所有子字典都具有相同的键,因此您可以从任意一个子字典中取出键:

keys = dct.values()[0].keys()

如果每个子字典可以有不同的键子集,则需要首先遍历dct以获得所有键:

keys = reduce(set.union, map(set, dct.values()))

有些人发现reduce很难理解,即使你真的只是把它当作"sum与不同的操作符"。对于他们,下面是如何显式地做同样的事情:

keys = set()
for subdct in dct.values():
    keys |= set(subdct)

现在,对于每个键的行,我们需要为每个子字典(即外部字典中的每个值)获取一列,其顺序是使用列表元素作为外部字典中的键。

因此,对于每个列item,我们想要获得与item中的键对应的外字典值,然后在结果子字典中获得与行key对应的值。这在英语中很难说,但在Python中,它只是:

dct[item][key]

如果不是所有的子字典都有相同的键,情况会稍微复杂一点:

dct[item].get(key, '')

所以,如果你不想要任何头文件,它会是这样的:

with open('output.csv', 'wb') as f:
    w = csv.writer(f, delimiter='t')
    for key in keys:
        w.writerow(dct[item].get(key, '') for item in lst)

要添加标题列,只需将标题(在本例中为key)附加到每一行:

with open('output.csv', 'wb') as f:
    w = csv.writer(f, delimiter='t')
    for key in keys:
        w.writerow([key], [dct[item].get(key, '') for item in lst])

注意,我将genexp转换为一个列表推导式,这样我就可以使用列表连接来添加key。从概念上讲,将其保留为迭代器,并加上itertools.chain是更清晰的,但在像这样的小迭代器的琐碎情况下,我认为这只会使代码更难阅读:

with open('output.csv', 'wb') as f:
    w = csv.writer(f, delimiter='t')
    for key in keys:
        w.writerow(chain([key], (dct[item].get(key, '') for item in lst)))

您还需要一个标题行。这就更简单了;它只是列表中的项,在标题列前加上一个空白列:

with open('output.csv', 'wb') as f:
    w = csv.writer(f, delimiter='t')
    w.writerow([''] + lst)
    for key in keys:
        w.writerow([key] + [dct[item].get(key, '') for item in lst])

然而,有两种方法可以使事情变得更简单。

首先,您可以使用OrderedDict,因此您不需要单独的键列表。如果您坚持使用单独的listdict,您仍然可以动态构建OrderedDict以使您的代码更易于阅读。例如:

od = collections.OrderedDict((item, dct[item]) for item in lst)

现在:

with open('output.csv', 'wb') as f:
    w = csv.writer(f, delimiter='t')
    w.writerow([''] + od.keys())
    for key in keys:
        w.writerow([key] + [subdct.get(key, '') for subdct in od.values()])

第二,你可以直接构建转置结构:

transposed = {key_b: {key_a: dct[key_a].get(key_b, '') for key_a in dct} 
              for key_b in keys}

然后按照明显的顺序遍历它(或者使用DictWriter为您处理列的顺序,并使用其writerows方法处理行,因此整个事情变成了一行代码)。

要在Python中存储对象以便以后可以重用它们,可以使用shelve模块。这是一个模块,可以让你将对象写入架子文件,然后重新打开它并检索对象,但它依赖于操作系统,所以如果你在Mac上创建了它,然后你想在Windows机器上打开它,它将不起作用。

import shelve
shelf = shelve.open("filename", flag='c') 
#with flag='c', you have to delete the old shelf if you want to overwrite it
dict1 = #something
dict2 = #something
shelf['key1'] = dict1
shelf['key2'] = dict2
shelf.close()

从架子上读取对象:

shelf_reader = shelve.open("filename", flag='r')
for k in shelf_reader.keys():
    retrieved = shelf_reader[k]
    print(retrieved) #prints the retrieved dictionary
shelf_reader.close()

这可能是一个意见问题,但我认为序列化(嵌套)字典的最佳(也是迄今为止最容易设置的)方法之一是使用JSON格式:

{ "key1" : { "subkey1" : "value1",
             "subkey2" : "value2" },
  "key2" : {"subkey3" : "value3"} }

最好的是可以使用内置的json模块在一行中完成(用于编码值或解码它们)!

让我们考虑您的字典是dico变量:

import json
save_file = open('save_file', 'w')
save_file.write( json.dumps(dico) )

如果数据保证被加载回Python,我建议简单地使用pickle而不用担心格式。如果它要被加载到另一种标准语言中,那么考虑使用json——大多数语言都有库来解析JSON格式的数据。

也就是说,如果您确实需要创建自己的格式,您可以这样做,将所有子字典中的所有键存储为CSV格式:

import csv
dict_keys = sorted(dict.keys())
with open("output.csv", "wb") as csvfile:
    writer = csv.writer(csvfile)
    writer.writerow(["Key"] + dict_keys)
    all_keys = reduce(set.union, (set(d) for d in dict.values()))
    for key in sorted(all_keys):
        writer.writerow([key] + [dict[k].get(key, "") for k in dict_keys])

相关内容

  • 没有找到相关文章

最新更新