用Python优雅地将CSV列拆分成独立数据结构的方式?
我正在学习Python。作为学习的一部分,我把一个用Java写的项目转到Python上。现在我遇到了一部分,我有一个CSV文件的标题列表,格式如下:
headers = [a, b, c, d, e, .....]
还有一些单独的列表,表示这些标题应该被分成哪些组,比如:
headers_for_list_a = [b, c, e, ...]
headers_for_list_b = [a, d, k, ...]
. . .
我想把CSV数据转换成字典,按照这些组来分类,比如:
list_a = [
{b:val_1b, c:val_1c, e:val_1e, ... },
{b:val_2b, c:val_2c, e:val_2e, ... },
{b:val_3b, c:val_3c, e:val_3e, ... },
. . .
]
在这里,比如说,val_1b是'b'列的第一行,val_3c是'c'列的第三行,等等。
我最初的“Java本能”是想这样做:
for row in data:
for col_num, val in enumerate(row):
col_name = headers[col_num]
if col_name in group_a:
dict_a[col_name] = val
elif headers[col_cum] in group_b:
dict_b[col_name] = val
...
list_a.append(dict_a)
list_b.append(dict_b)
...
不过,这种方法似乎效率不高,也不够简洁,跟Python程序员常说的优雅感觉不太一样。我想知道有没有更“Zen”的方法可以尝试,符合Python的哲学?
3 个回答
2
这不是实现你代码功能的最“pythonic”(最符合Python风格)的方法,但这个版本的代码因为使用了生成器表达式,所以写得更简洁一些:
from itertools import izip
for row in data:
dict_a = dict((col_name, val) for col_name, val in izip(headers, row) \
if col_name in group_a)
dict_b = dict((col_name, val) for col_name, val in izip(headers, row) \
if col_name in group_b)
list_a.append(dict_a)
list_b.append(dict_b)
另外,建议用集合来代替列表来表示 group_a
和 group_b
,因为在集合中使用 in
操作符会更快。不过,Jason Humber说得对,DictReader
的写法要优雅得多,看看下面这个版本:
from csv import DictReader
for row in DictReader(your_file, headers):
dict_a = dict((k, row[k]) for k in group_a)
dict_b = dict((k, row[k]) for k in group_b)
list_a.append(dict_a)
list_b.append(dict_b)
5
试试Python的CSV模块,特别是里面的DictReader类。
2
csv.DictReader
csv.DictReader 是 Python 中一个很方便的工具,用来读取 CSV 文件。CSV 文件是一种用逗号分隔的数据文件,通常用来存储表格数据,比如电子表格或者数据库的内容。
使用 DictReader 的时候,它会把每一行的数据变成一个字典(也就是一种数据结构),字典里的每个键对应 CSV 文件的列名,而每个值则是这一行对应列的内容。这样,你就可以通过列名来轻松访问数据,而不需要记住每一列的顺序。
简单来说,csv.DictReader 就是帮你把 CSV 文件里的数据变得更容易理解和使用。
import csv
groups = dict(a=headers_for_list_a, b=headers_for_list_b)
lists = dict((name, []) for name in groups)
for row in csv.DictReader(csvfile, fieldnames=headers):
for name, grp_headers in groups.items():
lists[name].append(dict((header, row[header]) for header in grp_headers))