我有一些字典:
d1 = {'name':'jon','age':4}
d2 = {'name':'joe','age':34,'height':100}
我这里没有列出其他字典,它们有一些不同的关键字,但它们与d1
和d2
有一些共同的关键字。
import csv
with open('file.csv', 'a') as f:
wr = csv.writer(f)
wr.writerow(d1.values())
wr.writerow(d2.values())
当然,这并不能将数据放在正确的列中。它也不需要标头。我如何设置它,使每个字典中的每个键都成为一个标题,并且在将信息写入CSV时将值放在正确的位置?
尝试使用csv.DictWriter(f, fieldnames=csv_columns)
而不是csv.writer(f)
查看此处的文档。至于csv_columns
,如果你事先不知道所有的列名,你可以在所有字典中循环,找到唯一的字典并将它们添加到列表中。
我在下面写了一个例子。
import csv
d1 = {'name':'jon', 'age':4}
d2 = {'name':'joe', 'age':34, 'height':100}
csv_columns = ['name', 'age', 'height']
with open('file.csv', 'a') as f:
wr = csv.DictWriter(f, fieldnames=csv_columns)
wr.writeheader()
wr.writerow(d1)
wr.writerow(d2)
我认为处理这一问题的最佳方法是创建一个跟踪添加到其中的所有dict的类,然后为您编写文件。
这个类将允许您添加任意数量的dict,并跟踪所有字段,并将它们适当地添加到文件中。
class CsvDictWriter:
def __init__(self):
self.dicts = []
self.fields = set()
def add_dict(self, obj: dict):
self.dicts.append(obj)
self.fields.update(obj.keys())
def write(self, file_name: str):
with open(file_name, 'w') as fp:
dw = DictWriter(fp, self.fields, restval='')
dw.writeheader()
for obj in self.dicts:
dw.writerow(obj)
d1 = {'name': 'jon', 'age': 4}
d2 = {'name': 'joe', 'age': 34, 'height': 100}
cdw = CsvDictWriter()
cdw.add_dict(d1)
cdw.add_dict(d2)
cdw.write('file.csv')
您需要一个所有可能键的列表,以及将它们写入csv的顺序。您将无法构建文件";在飞行中";因为你不知道每本字典包含哪些键,按什么顺序排列;除非在开始将所有词典写入文件之前检查它们。
使用标题(键(列表和DictWriter,您可以逐个处理并输出到文件中。
DiscWriter类参数有一个restval
,您需要它,因为并非所有字典都有所有键。它被描述为:
如果字典在字段名称中缺少键,可选的restval参数指定要写入的值。
我发现这不是很好的性能,但它应该可以在不需要知道所有列的名称的情况下工作。这将生成一个制表符分隔的csv字符串。结果可以很容易地写入文件
def exportArrayDicToCSV(arrayDict):
csvData = {}
headerString = ''
bodyString = ''
print(f"Processing Dictionary List")
for rowDataIndex in range(0, len(arrayDict)):
print(f"{rowDataIndex + 1} out of {len(arrayDict)} rows processed")
rowData = arrayDict[rowDataIndex]
for header in rowData:
if header not in csvData:
csvData[header] = [""] * len(arrayDict)
csvData[header][rowDataIndex] = rowData[header]
headerList = list(csvData.keys())
headerString = "t".join(headerList)
print(f"generating CSV string")
for rowDataIndex in range(0, len(arrayDict)):
print(f"{rowDataIndex + 1} out of {len(arrayDict)} rows processed")
rowDataString = ''
for fieldIndex in range(0, len(headerList)):
rowDataString = f"{rowDataString}{csvData[headerList[fieldIndex]][rowDataIndex]}"
if fieldIndex < len(headerList) - 1:
rowDataString = f"{rowDataString}t"
bodyString = f"{bodyString}{rowDataString}"
if rowDataIndex < len(arrayDict)-1:
bodyString = f"{bodyString}n"
return f"{headerString}n{bodyString}"