首先,如果我了解您的结构,则列表只是为外部字典排序键的一种方式,并且您的很多复杂性是试图将这两者结合使用来模拟有序字典。如果是这样,有一个更简单的方法来做到这一点:使用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
,我们要获取对应于键 in 的外部字典值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
,因此您不需要单独的密钥列表。如果您坚持使用单独的list
and dict
,您仍然可以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}
然后以明显的顺序对其进行迭代(或使用 aDictWriter
为您处理列的顺序,并使用它的writerows
方法来处理行,因此整个事情变成了单线)。