【问题标题】:Hierarchical JSON from csv python来自csv python的分层JSON
【发布时间】:2016-09-12 06:00:42
【问题描述】:

我有一个 csv 结构的数据集,如下所示:

Name,code,count
Adam,01,48
Bill,01,32
Chris,01,4
Carl,01.01,5
Dave,01.01,1
David,01.01,1
Eric,01.01.01,26
Earl,01.01.01.01,2
Frank,01.01.01.01,2
Greg,01.01.01.02,2
Harold,01.01.01.03,7
Ian,01.01.01.03,3
Jack,01.01.01.03,1
John,01.01.01.04,10
Kyle,01.01.01.04,2
Larry,01.01.03.01,3
Mike,01.01.03.01.01,45
Nick,01.01.03.01.01.01,1
Oliver,01.01.03.01.01.02,16
Paul,01.01.03.01.01.03,23

我想在 python 中创建一个字典,其中“名称”和“计数”是键:值对(这很容易),但我想根据“代码”编号组织一个层次结构。即 01.01 是 01 的孩子,我不确定如何迭代数据以实现这一点。我最终想做一个整个结构的 json 转储,但它是如何构建让我失望的层次结构。非常感谢任何帮助。

【问题讨论】:

  • 您能否提供所需输出的示例?开头有三个 01 元素 - 01.01 元素应该如何适应层次结构?分配给哪个元素?
  • 你能展示一下“层次结构”的外观吗?
  • 在 csv 的某些行上出现的最多 5 个其他字段是什么?

标签: python json csv hierarchy


【解决方案1】:

在 Python 中实现树结构的一种简单而优雅的方法是使用递归 defaultdict

import csv, json
from collections import defaultdict

def tree():
    return defaultdict(tree)

d = tree()

with open('data.txt', 'rb') as f:
    reader = csv.reader(f, delimiter=',')

    for name, code, count in list(reader)[1:]:
        path = code.split('.')
        iter_node = d
        for node in path:
            iter_node = iter_node[node]
        iter_node['values'][name] = count

print json.dumps(d, indent=2)

{
  "01": {
    "values": {
      "Chris": "4", 
      "Bill": "32", 
      "Adam": "48"
    },
    "01": {
      "values": {
        "Dave": "1", 
        "Carl": "5", 
        "David": "1"
      },
      "03": {
        "01": {
          "01": {
            "02": {
              "values": {
                "Oliver": "16"
              }
            }, 
            "03": {
              "values": {
                "Paul": "23"
              }
            }, 
            "01": {
              "values": {
                "Nick": "1"
              }
            }, 
            "values": {
              "Mike": "45"
            }
          }, 
          "values": {
            "Larry": "3"
          }
        }
      }, 
      "01": { 
        "values": {
          "Eric": "26"
        }, 
        "02": {
          "values": {
            "Greg": "2"
          }
        }, 
        "03": {
          "values": {
            "Harold": "7", 
            "Ian": "3", 
            "Jack": "1"
          }
        }, 
        "01": {
          "values": {
            "Earl": "2", 
            "Frank": "2"
          }
        },
        "04": {
          "values": {
            "John": "10", 
            "Kyle": "2"
          }
        }
      }
    }
  }
}

【讨论】:

    【解决方案2】:

    下面的 sn-p 查找树的所有节点而不实际创建一个。 Python 中的树和链表实现效率低下 (Beazley)。

    from itertools import groupby
    import csv
    
    with open('csvfile.csv') as f:
        reader = csv.DictReader(f)
    
    groups = groupby(reader, key=lambda row: row['code'])
    nodes = {code: {item['Name']: item['count'] for item in group} for code,group in groups}
    
    {'01': {'Adam': '48', 'Bill': '32', 'Chris': '4'},
     '01.01': {'Carl': '5', 'Dave': '1', 'David': '1'},
     '01.01.01': {'Eric': '26'},
     '01.01.01.01': {'Earl': '2', 'Frank': '2'},
     '01.01.01.02': {'Greg': '2'},
     '01.01.01.03': {'Harold': '7', 'Ian': '3', 'Jack': '1'},
     '01.01.01.04': {'John': '10', 'Kyle': '2'},
     '01.01.03.01': {'Larry': '3'},
     '01.01.03.01.01': {'Mike': '45'},
     '01.01.03.01.01.01': {'Nick': '1'},
     '01.01.03.01.01.02': {'Oliver': '16'},
     '01.01.03.01.01.03': {'Paul': '23'}}
    

    【讨论】:

    • 感谢 C 熊猫!这很好用。您可以编辑您的回复以将这些行放入: import csv f = open("somefile.csv","r") .....我认为有些人会需要它们
    • @miltonjbradley 哪一行 bdw?
    • 我喜欢简洁的代码。但是,它并没有明确树结构。
    • @schwobaseggl 我知道这一点。因为我不知道等级制度是什么样子的。我无法为结果字典键提供任何语义。我的 python 树永远是dict。但我想知道它长什么样。
    • @CPanda 我认为如果你从内部dicts 中删除多余的code 并使用name:count 键值对,它会更干净。这将使结果不那么冗长而不会丢失信息。
    【解决方案3】:

    我猜你想做一些标准的树结构,在那里你可以访问一个树结构,使用路径访问时会自动创建缺少的节点。

    类似的东西。

    class Node:
        def __init__( self, parent=None ):
            self.parent = parent
            self.store = {}
            self.children = {}
    
        def create_child( self, child_name ):
            self.children[ child_name ] = Node( self )
    
        #ancestry_line is a list of names
        def recursive_get_child( self, ancestry_line_names ):
            if len(ancestry_line_names) == 0:
                return self
            else:
                next_ancestor = ancestry_line_names[0]
                other_ancestors = ancestry_line_names[1:]
                if next_ancestor not in self.children:
                    self.create_child( next_ancestor )
                return self.children[ next_ancestor ].recursive_get_child( other_ancestors )
    

    您需要做的就是创建一个根节点,并通过路径从它访问正确的节点。

    root = Node()
    for name, code, count in some_data_iterator():
        ancestry_line = code.split(".")
        root.get( ancestry_line ).store[ name ] = count
    

    然后您可以在Node 中创建一个方法,将Node 结构转换为可用于转储到json 中的纯字典结构。

    【讨论】:

    • 感谢您的回复。这适用于一个小列表。当我使用整个文件时,我得到了一个“太大而无法解压”的错误
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-28
    • 2016-03-21
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多