2015-04-17 3 views
4

У меня есть файл CSV в следующем виде:Преобразование данных CSV в список в словаре

Name_1,2,K,14 
Name_1,3,T,14 
Name_1,4,T,18 
Name_2,2,G,12 
Name_2,4,T,14 
Name_2,6,K,15 
Name_3,2,K,12 
Name_3,3,T,15 
Name_3,4,G,18 

И я хочу, чтобы преобразовать его в словарь, где Name_x является ключом и соответствующие данные значения в виде списка , Что-то вроде этого:

{'Name_1': [[2, 'K', 14], [3, 'T', 14], [4, 'T', 18]], 
'Name_2': [[4, 'T', 14], [4, 'T', 14], [6, 'K' ,15]], 
...} 

До сих пор, я думаю, что я должен использовать использовать defaultdict:

from collections import defaultdict 
d = defaultdict(list) 

Но как я append данные в d? Я знаю, что defaultdict не имеет метода append.

+0

'd [ключ] .append (new_val)'? – jonrsharpe

ответ

6

Вы должны использовать имя в качестве ключа и добавьте кусочек строки в качестве значения, не будет никакого порядка, используя нормальный или defaultdict:

import csv 
from collections import defaultdict 

with open('in.csv') as f: 
    r = csv.reader(f) 
    d = defaultdict(list) 
    for row in r: 
     d[row[0]].append(row[1:]) 
print(d) 

Если вы хотите сохранить заказ вы нужен OrderedDict:

from collections import OrderedDict 

with open('in.csv') as f: 
    r = csv.reader(f) 
    od = OrderedDict() 
    for row in r: 
     # get key/ first element in row 
     key = row[0] 
     # create key/list paring if it does not exist, else just append the value 
     od.setdefault(key, []).append(row[1:]) 
print(od) 

Выход:

OrderedDict([('Name_1', [['2', 'K', '14'], ['3', 'T', '14'], ['4', 'T', '18']]), ('Name_2', [['2', 'G', '12'], ['4', 'T', '14'], ['6', 'K', '15']]), ('Name_3', [['2', 'K', '12'], ['3', 'T', '15'], ['4', 'G', '18']])]) 

Вы могли бы также у се GroupBy, если имена сгруппированы, которые будут групповые элементы на основе первого элемента/имени в каждой строке:

import csv 
from collections import OrderedDict 
from itertools import groupby 
from operator import itemgetter 

with open('in.csv') as f: 
    r = csv.reader(f) 
    od = OrderedDict() 
    for k, v in groupby(r, key=itemgetter(0)): 
     od[k] = [sub[1:] for sub in v] 

Если вы используете python3 можно распаковать с помощью *:

with open("in.csv") as f: 
    r = csv.reader(f) 
    od = OrderedDict() 
    for row in r: 
     key, *rest = row 
     od.setdefault(key, []).append(rest) 


import csv 
from collections import OrderedDict 
from itertools import groupby 
from operator import itemgetter 

with open('in.csv') as f: 
    r = csv.reader(f) 
    od = OrderedDict() 
    for k, v in groupby(r, key=itemgetter(0)): 
     od[k] = [sub for _, *sub in v] 
print(od) 
+0

Незначительное улучшение: key = row.pop (0), а затем od.setdefault (ключ, []). Append (row) – simleo

+0

Это работает, спасибо! Приятно вам добавить возможность OrderedDict - это именно то, что я хочу. Действительно ли можно получить значения по индексу? Так, например, 'Name_1 [1]' даст мне «K», «T», «T». Я могу получить доступ к единственной букве '[" Name_1 "] [1] [1]', но мне нужны все буквы (в том же порядке). – Hjalte

+0

@Hjalte, обязательно просто 'print (list (zip (* od [" Name_1 "])) [1])', который будет транспонировать подписи или 'print ([sub [1] для sub в od [" Name_1 " ]]) ' –

-1

Off верхней моей головы (потому что я не слишком знаком с defaultdict), это должно делать примерно то, что вы хотите.

данных является строка CSV

obj = {} 

data = data.split('\n') 
for row in data: 
    row = row.split(',') 
    if row[0] in obj: 
     obj[row[0]].append(row[1:]) 
    else: 
     obj[row[0]] = [row[1:]] 

print obj 
+0

Любопытно, почему -1? – enigma

+0

ах, достаточно справедливо – enigma

0
txtcsv="""Name_1,2,K,14 
Name_1,3,T,14 
Name_1,4,T,18 
Name_2,2,G,12 
Name_2,4,T,14 
Name_2,6,K,15 
Name_3,2,K,12 
Name_3,3,T,15 
Name_3,4,G,18""" 

def save(): 
    with open("test.csv","w") as f: 
     f.write(txtcsv) 


if __name__ == "__main__": 
    save() 
    with open("test.csv") as f: 
     d = {} 
     for l in f.readlines(): 
      name, val = l.rstrip().split(",", 1) 
      d.setdefault(name, []).append(val.split(",")) 
     print (d) 
+0

Могу я знать, почему -1? – daouzli

+1

не мой нисходящий канал, но нет необходимости читать все строки в памяти, автоматически закрывая файлы, чтобы функция f.close() была избыточной. Вы также можете использовать rstrip для удаления из конца строки и использовать dict.setdefault для обработки повторяющихся ключей. –

+0

@PadraicCunningham, конечно, для закрытия! Правильно, обезглавить обе стороны нецелесообразно! Я не привык использовать setdefault, но это действительно лучше. Спасибо! – daouzli

-2

Придерживаться defaultdict, у него есть метод добавления. Используйте его, как показано ниже:

>>> from collections import defaultdict 
>>> a = [['even', str(i)] if i%2==0 else ['odd', i] for i in range(10)] 
>>> a 
[['even', '0'], ['odd', 1], ['even', '2'], ['odd', 3], ['even', '4'], ['odd', 5], ['even', '6'], ['odd', 7], ['even', '8'], ['odd', 9]] 
>>> d = defaultdict(list) 
>>> for i in a: 
...  d[i[0]].append(i[1]) 
... 
... 
>>> dict(d) 
{'even': ['0', '2', '4', '6', '8'], 'odd': [1, 3, 5, 7, 9]} 

Это объясняется в питона документации с примерами @defaultdict-examples

+0

Хотя эта ссылка может ответить на вопрос, лучше включить здесь основные части ответа и предоставить ссылку для справки. Ответные ссылки могут стать недействительными, если связанная страница изменится. – uKolka

+0

спасибо за отзыв uKolka. Теперь я изменил свой ответ, например. :) Другие, кто проголосовал за, оценили, могли бы вы дать некоторые указания о том, как улучшить мои ответы. – akshat

+0

http://stackoverflow.com/help/how-to-answer – uKolka