Самый элегантный способ разбить столбцы CSV на отдельные структуры данных, используя Python? - PullRequest
2 голосов
/ 05 мая 2010

Я пытаюсь забрать Python. В рамках процесса обучения я портирую проект, написанный на Java, на Python. Сейчас я нахожусь в разделе, где у меня есть список заголовков CSV вида:

headers = [a, b, c, d, e, .....]

и отдельные списки групп, на которые следует разбить эти заголовки, например ::1004*

headers_for_list_a = [b, c, e, ...]
headers_for_list_b = [a, d, k, ...]
. . .

Я хочу взять данные CSV и превратить их в данные, основанные на этих группах, например ::100100

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. Есть ли более "дзен-подобный" способ, которым я должен придерживаться философии Python?

Ответы [ 3 ]

5 голосов
/ 05 мая 2010

Попробуйте модуль CSV в Python, в частности класс DictReader.

2 голосов
/ 05 мая 2010

csv.DictReader

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))
2 голосов
/ 05 мая 2010

Не обязательно самый питонический способ достичь того же, что и ваш код, но эта версия вашего кода несколько более кратка из-за использования выражений генератора:

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 работает быстрее на наборах. Но Джейсон Хамбер прав, 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...