用于将复杂的展平数据转换为JSON的Python脚本

时间:2014-07-02 22:18:57

标签: python json csv

对于模糊的标题感到抱歉,我需要一些Python魔法的帮助,并且无法想到任何更具描述性的内容。

我有一个固定的JSON数据结构,我需要将CSV文件转换为。结构是固定的,但与列表等深深嵌套。它与此类似,但更复杂:

{
    "foo" : bar,
    "baz" : qux,
    "nub" : [
        {
            "bub": "gob",
            "nab": [
                {
                    "nip": "jus",
                    "the": "tip",
                },
                ...
            ],
        },
        ...
    ],
    "cok": "hed"
}

希望你明白了。列出列表上的列表等等。我的csv可能看起来像这样:

foo, baz, nub.bub, nub.nab.nip, nub.nab.the, cok

bar, qux, "gob" ,,,, "hed"

,,,,, "nab", "jus","tip",,

,,,,, "nab", "other", "values",,

很抱歉,如果这很难阅读,但基本的想法是,如果列出的项目将在下一行,并重复值以表示哪些子列表属于什么。

我不是在寻找任何人来解决这个烂摊子的问题,也许是关于技术或事情的一些指示。

现在我有一个粗略的计划:

我首先将标题转换为包含键的元组列表。对于每组行(项目),我将创建我的模板dict的副本。我有一个函数,它将从一个键元组设置一个dict值,除非它找到一个列表。在这种情况下,我将调用一个时髦的递归函数并将其传递给我的迭代器,并继续填充该函数中的dict,并在找到新列表时进行递归调用。

我也可以做很多硬编码,但那有什么好玩的呢?

这就是我的故事。再次,只是寻找一些关于最佳方法的指针。我写的很快,所以可能有点令人困惑,如果有任何更多的信息会有所帮助,请告诉我。谢谢!

1 个答案:

答案 0 :(得分:1)

您的JSON格式不正确。此外,您的json必须不包含数组才能达到您想要的效果。

def _tocsv(obj, base=''):
    flat_dict = {}
    for k in obj:
        value = obj[k]
        if isinstance(value, dict):
            flat_dict.update(_tocsv(value, base + k + '.'))
        elif isinstance(value, (int, long, str, unicode, float, bool)):
            flat_dict[base + k] = value
        else:
            raise ValueError("Can't serialize value of type "+ type(value).__name__)
    return flat_dict

def tocsv(json_content):
    #assume you imported json
    value = json.loads(json_content)
    if isinstance(value, dict):
        return _tocsv(value)
    else:
        raise ValueError("JSON root object must be a hash")

会让你扁平化:

{
    foo: "nestor",
    bar: "kirchner",
    baz: {
        clorch: 1,
        narf: 2,
        peep: {
            ooo: "you suck"
        }
    }
}

成像:

{"foo": "nestor", "bar": "kirchner", "baz.clorch": 1, "baz.narf": 2, "baz.peep.ooo": "you suck"}

密钥不保留任何特定订单。如果要保留顺序,可以将flat_dict = {}替换为OrderedDict的构造。

假设您有一系列这样平坦的词组:

def tocsv_many(json_str):
    #assume you imported json
    value = json.loads(json_content)
    result = []
    if isinstance(value, list):
        for element in value:
            if isinstance(element, dict):
                result.append(_tocsv(element))
            else:
                raise ValueError("root children must be dicts")
    else:
        raise ValueError("The JSON root must be a list")
flat_dicts = tocsv_many(yourJsonInput)
你可以:

  1. 创建一个csvlines = []列表,其中包含ur文件的csv行。
  2. 创建一个keysSet = set(),其中包含可能的键。
  3. 对于您拥有的每个dict,将.keys()添加到集合中。正常设置不保证密钥顺序;使用排序集代替。最后我们得到第一个CSV行。

     for flat_dict in flat_dicts:
         keysSet.extend(flat_dict.keys())
     csvlines.appens(",".join(keysSet))
    
  4. 对于你拥有的每个dict(再次迭代),你生成一个这样的数组:

     for flat_dict in flat_dicts:
         csvline = ",".join([json.dumps(flat_dict.get(keyInSet, '')) for keyInSet in keysSet])
         csvlines.append(csvline)
    
  5. voilah!你有csvlines

  6. 中的行