从CSV文件导入/导出嵌套字典
我有一个CSV文件,里面的数据是这样排列的:
X,a,1,b,2,c,3
Y,a,1,b,2,c,3,d,4
Z,l,2,m,3
我想把这个CSV文件导入,创建一个嵌套字典,格式应该像这样。
data = {'X' : {'a' : 1, 'b' : 2, 'c' : 3},
'y' : {'a' : 1, 'b' : 2, 'c' : 3, 'd' : 4},
'Z' : {'l' : 2, 'm' :3}}
在我写的程序中更新了这个字典(这部分我已经搞定了),接下来我想把这个字典导出到同一个CSV文件里,覆盖或更新原来的内容。不过,我希望它的格式和之前的CSV文件一样,这样我才能再次导入。
我一直在尝试导入,现在有了这些进展:
import csv
data = {}
with open('userdata.csv', 'r') as f:
reader = csv.reader(f)
for row in reader:
data[row[0]] = {row[i] for i in range(1, len(row))}
但是这样做不行,因为数据的排列不对。有些数字是其他数字的子键,字母的位置也不对,等等。我甚至还没开始导出部分呢。有没有什么建议?
4 个回答
我比较懒,所以我可能会这样做:
import csv
data = {}
with open('userdata.csv', 'rb') as f:
reader = csv.reader(f)
for row in reader:
data[row[0]] = dict(zip(row[1::2], map(int,row[2::2])))
这样做是有效的,因为 row[1::2]
会从索引1开始,获取每隔一个的元素,而 row[2::2]
则是从索引2开始获取每隔一个的元素。接着,zip
会把这些元素配对成一个元组,然后我们把这个元组传给 dict
。这样就得到了:
{'Y': {'a': 1, 'c': 3, 'b': 2, 'd': 4},
'X': {'a': 1, 'c': 3, 'b': 2},
'Z': {'m': 3, 'l': 2}}
(注意,我把你的 open
改成了 'rb'
,这是Python 2中正确的写法:如果你使用的是 3
,那么应该用 'r', newline=''
。)
当然可以!请看下面的内容:
在编程中,有时候我们需要让程序做一些事情,比如处理数据、显示信息或者与用户互动。为了实现这些功能,我们通常会使用一些特定的代码和命令。
有些时候,程序可能会出现错误,这些错误可能是因为代码写得不够准确,或者是因为我们没有考虑到某些特殊情况。解决这些问题的过程就叫做“调试”。调试的目的是找到错误的原因,并修复它,让程序能够正常运行。
在调试的过程中,我们可以使用一些工具和方法,比如打印输出一些信息,查看程序在运行时的状态,或者使用调试器来逐步执行代码,观察每一步的结果。
总之,调试是编程中非常重要的一部分,它帮助我们确保程序能够按照预期工作。
from collections import defaultdict
data_lines = """X,a,1,b,2,c,3
Y,a,1,b,2,c,3,d,4
Z,l,2,m,3""".splitlines()
data = defaultdict(dict)
for line in data_lines:
# you should probably add guards against invalid data, empty lines etc.
main_key, sep, tail = line.partition(',')
items = [item.strip() for item in tail.split(',')]
items = zip(items[::2], map(int, items[1::2])
# data[main_key] = {key : value for key, value in items}
data[main_key] = dict(items)
print dict(data)
# {'Y': {'a': '1', 'c': '3', 'b': '2', 'd': '4'},
# 'X': {'a': '1', 'c': '3', 'b': '2'},
# 'Z': {'m': '3', 'l': '2'}
# }
你可以使用来自itertools
的grouper
这个方法:
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return itertools.izip_longest(fillvalue=fillvalue, *args)
这个方法会把你的数据分组,变成你想要的a1/b2/c3这样的配对。所以在你的循环中,你可以这样写data[row[0]] = {k: v for k, v in grouper(row[1:], 2)}
。
因为你不需要保持顺序,所以用一种相对简单的方法就可以解决问题:
import csv
# import
data = {}
with open('userdata.csv', 'r') as f:
reader = csv.reader(f)
for row in reader:
a = iter(row[1:])
data[row[0]] = dict(zip(a, a))
# export
with open('userdata_exported.csv', 'w') as f:
writer = csv.writer(f)
for key, values in data.items():
row = [key] + [value for item in values.items() for value in item]
writer.writerow(row)
后面这部分可以通过只调用一次csv.writer
的writerows()
方法来更高效地完成,并且可以传入一个生成器表达式。
# export2
with open('userdata_exported.csv', 'w') as f:
writer = csv.writer(f)
rows = ([key] + [value for item in values.items() for value in item]
for key, values in data.items())
writer.writerows(rows)