从CSV文件导入/导出嵌套字典

2 投票
4 回答
1677 浏览
提问于 2025-04-18 01:38

我有一个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 个回答

0

我比较懒,所以我可能会这样做:

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=''。)

0

当然可以!请看下面的内容:

在编程中,有时候我们需要让程序做一些事情,比如处理数据、显示信息或者与用户互动。为了实现这些功能,我们通常会使用一些特定的代码和命令。

有些时候,程序可能会出现错误,这些错误可能是因为代码写得不够准确,或者是因为我们没有考虑到某些特殊情况。解决这些问题的过程就叫做“调试”。调试的目的是找到错误的原因,并修复它,让程序能够正常运行。

在调试的过程中,我们可以使用一些工具和方法,比如打印输出一些信息,查看程序在运行时的状态,或者使用调试器来逐步执行代码,观察每一步的结果。

总之,调试是编程中非常重要的一部分,它帮助我们确保程序能够按照预期工作。

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'}
# }
0

你可以使用来自itertoolsgrouper这个方法:

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)}

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.writerwriterows()方法来更高效地完成,并且可以传入一个生成器表达式

# 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)

撰写回答