2013-05-01 1 views
1

У меня есть CSV-файл, который отформатирован примерно так:Чтение из конечных множеств столбцов CSV и outputing как строки для конкретной схемы JSON

name subname value1 value2 
a  a  1  21 
a  a  2  22 
a  a  3  23 
a  a  4  24 

b  a  5  25 
b  a  6  26 
b  a  7  27 
b  a  8  28 

c  c  9  29 
c  c  10  30 
c  c  11  31 
c  c  12  32 
.... 
etc 

Использование простого CSV для JSon сценария мне удалось вывести каждая строка как действительная запись json, однако это очень избыточно, так как существует так много повторяющихся значений.

Я пытаюсь прочитать этот файл и выводит его в форму, которая выглядит так же, как это:

[ 
{ 
    "name":"a", 
    "subname":"a", 
    "data": { 
     "attr1":{"name":"value1", "values":[1,2,3,4]}, 
     "attr2":{"name":"value2", "values":[21,22,23,24]} 
    } 
}, 
{ 
    "name":"b", 
    "subname":"a", 
    "data": { 
     "attr1":{"name":"value1", "values":[5,6,7,8]}, 
     "attr2":{"name":"value2", "values":[25,26,27,28]} 
    } 
}, 
{ 
    "name":"c", 
    "subname":"c", 
    "data": { 
     "attr1":{"name":"value1", "values":[9,10,11,12]}, 
     "attr2":{"name":"value2", "values":[29,30,31,32]} 
    } 
}, 
.... 
etc 
] 

Я знаю, что сценарий должен работать что-то вроде этого:

loop until no more rows: 
skip row 1 
for the next 4 rows 
    { 
     "name":row 1, column 1 , 
     "subname":row 1, column 2 , 
     "data": { 
      "attr1":{"name":"value1", "values":[row 1 to 4, column 3]} 
      "attr2":{"name":"value2", "values":[row 1 to 4, column 4]} 
     } 
    } 

С этим конкретный набор данных всегда будет иметь этот шаблон (однако фактические данные содержат больше записей и столбцов). Я знаю, что хотел бы для вывода, но я не совсем уверен, как его реализовать.

Как мне это сделать с помощью python? Приветствуются любые предложения и решения.

редактировать: Вот решение в прямом JavaScript с помощью underscore.js

var headers = this.get('headers') 
var grid = this.get('grid') 
var transposed = grid.transpose() 
var tables = []; 
var grid = 
var rows = [] 
keys = ["name", "subname"] 

var numberOfEntries = grid.length - 2; 
_(numberOfEntries).times(function(n) {keys.push("attr" + (n+1)) }) 

_.each(transposed, function(row) { 
    rows.push(_.object(keys, row)) 
}) 

var names = _.uniq(grid[0]) 

_.each(names, function(name) { 
    var entries = _.where(rows, {name: name}) 

    _.each(entries, function(entry) { 
    var exists = _.where(tables, {name: entry.name, subname: entry.subname}) 
    var obj = {}; 
    if(exists.length > 0) { 
     obj = exists[0] 
    } 
    else { 
     obj = {name: entry.name, subname: entry.subname, data: {}} 
     tables.push(obj)   
    } 

    _(numberOfEntries).times(function(n) { 
     var i = n + 1; 
     if(!obj.data["attr" + i]) { 
     obj.data["attr" + i ] = {"name":headers[n+2], "values": []}; 
     } else { 
     obj.data["attr" + i].values.push(entry["attr" + i]) 
     } 
    }) 
    }) 
}) 

ответ

1

Я бы итерации по каждой строке CSV и использовать словарь, который уже прошел строки (я предполагаю, что сочетание имени/подимени)

data = {} 
for row in words: 
    if not row["name"] + "-" + row["subname"] in data: 
     data[row["name"] + "-" + row["subname"]] = { 
      "name": row["name"], 
      "subname": row["subname"], 
      "data": { 
       "attr1": {"name":"value1", "values": []}, 
       "attr2": {"name":"value2", "values": []} 
      } 
     } 
    data[row["name"] + "-" + row["subname"]]["data"]["attr1"]["values"].append(row["value1"]) 
    data[row["name"] + "-" + row["subname"]]["data"]["attr2"]["values"].append(row["value2"]) 
+0

Большое спасибо. Это отлично. – nimchimpsky

0

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

import csv,pprint 
from itertools import groupby 

with open('tsv.csv') as f: 
    values = [] 
    reader = csv.DictReader(f) 
    for group in (list(g) for k,g in groupby(reader,lambda r: r["name"])): #group by the name column of each row 
     #group looks like [ {'subname': 'a', 'value2': '25', 'value1': '5', 'name': 'b'},...] 
     groupRep = {"name":group[0]["name"], #get the name from the first group 
        "subname":group[0]["subname"], #get the subname from the first group 
        "data":{ 
         "attr1":{"name":"value1","values":[]}, #make place to store value1s 
         "attr2":{"name":"value2","values":[]} #make place to store value2s 
         } 
        } 
     for row in group: 
     #each row is a dictionary like {'subname': 'a', 'value2': '25', 'value1': '5', 'name': 'b'} 
      groupRep["data"]["attr1"]["values"].append(row["value1"]) 
      groupRep["data"]["attr2"]["values"].append(row["value2"]) 
     #store the representation of the group in values 
     values.append(groupRep) 

Довольно печати:

PP = pprint.PrettyPrinter()  
PP.pprint(values) 

Получает:

[{'data': {'attr1': {'name': 'value1', 'values': ['1', '2', '3', '4']}, 
      'attr2': {'name': 'value2', 'values': ['21', '22', '23', '24']}}, 
    'name': 'a', 
    'subname': 'a'}, 
{'data': {'attr1': {'name': 'value1', 'values': ['5', '6', '7', '8']}, 
      'attr2': {'name': 'value2', 'values': ['25', '26', '27', '2']}}, 
    'name': 'b', 
    'subname': 'a'}, 
{'data': {'attr1': {'name': 'value1', 'values': ['9', '1', '1', '1']}, 
      'attr2': {'name': 'value2', 'values': ['29', '30', '31', '32']}}, 
    'name': 'c', 
    'subname': 'c'}] 
+0

Это действительно здорово. Вы знаете, как реализовать это в прямом javascript? – nimchimpsky

+0

Сегодня я пойду позже. – HennyH

+0

Я бы использовал такую ​​библиотеку http://jquery-csv.googlecode.com/git/examples/basic-usage.html – HennyH