用Python优雅地将CSV列拆分成独立数据结构的方式?

2 投票
3 回答
1905 浏览
提问于 2025-04-15 22:21

我正在学习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_agroup_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))

撰写回答