【问题标题】:Converting JSON to CSV with part of JSON value as row headers使用部分 JSON 值作为行标题将 JSON 转换为 CSV
【发布时间】:2019-06-11 21:40:01
【问题描述】:

我刚刚开始学习 Python,我的任务是将 JSON 转换为 CSV 文件,以分号作为分隔符并具有三个约束。 我的 JSON 是:

{"_id": "5cfffc2dd866fc32fcfe9fcc", 
"tuple5": ["system1/folder", "system3/folder"], 
"tuple4": ["system1/folder/text3.txt", "system2/folder/text3.txt"], 
"tuple3": ["system2/folder/text2.txt"], 
"tuple2": ["system2/folder"], 
"tuple1": ["system1/folder/text1.txt", "system2/folder/text1.txt"], 
"tupleSize": 3}

输出的 CSV 格式应为:

system1                  ;           system2        ;             system3
system1/folder           ;             ~            ;            system3/folder
system1/folder/text3.txt ; system2/folder/text3.txt ;              ~
~                        ; system2/folder/text2.txt ;              ~
~                        ; system2/folder           ;              ~
system1/folder/text1.txt ; system2/folder/text1.txt ;              ~

所以三个约束是tupleSize 将指示行数,数组元素的第一部分即sys1sys2sys3 将是数组元素,最后只有那些元素属于特定系统的值将包含在 CSV 文件中(其余为 ~)。

我发现了一些关于 Python 转换的帖子,例如 thisthis。他们都没有任何与这些相关的限制,我无法弄清楚如何解决这个问题。

有人可以帮忙吗?

编辑:我应该提到数组元素是动态的,因此 CSV 文件中的行标题可能会有所不同。

【问题讨论】:

    标签: python json csv


    【解决方案1】:

    你想做的事情相当充实,所以如果它只是一个 Python 学习练习,我建议你从更基本的任务开始。

    我还认为你已经把大多数人所说的行和列颠倒了——所以请注意,下面的所有内容,包括代码,使用它们的方式与你在问题中使用它们的方式相反。

    无论如何,下面的代码首先对数据进行预处理,以确定 CSV 文件的列或字段名将是什么,并确保它们的数量与 'tupleSize' 键指定的一样。

    假设满足约束,然后它再次遍历数据并从每个键值中提取列/字段值,将它们放入字典中,字典的内容表示要写入输出文件的行 - 然后完成后会这样做。

    更新

    修改为删除 JSON 对象字典中所有以“_id”开头的键。

    import csv
    import json
    import re
    
    
    SEP = '/'  # Value sub-component separator.
    id_regex = re.compile(r"_id\d*")
    json_string = '''
        {"_id1": "5cfffc2dd866fc32fcfe9fc1",
         "_id2": "5cfffc2dd866fc32fcfe9fc2",
         "_id3": "5cfffc2dd866fc32fcfe9fc3",
         "tuple5": ["system1/folder", "system3/folder"],
         "tuple4": ["system1/folder/text3.txt", "system2/folder/text3.txt"],
         "tuple3": ["system2/folder/text2.txt"],
         "tuple2": ["system2/folder"],
         "tuple1": ["system1/folder/text1.txt", "system2/folder/text1.txt"],
         "tupleSize": 3}
    '''
    
    data = json.loads(json_string)  # Convert JSON string into a dictionary.
    
    # Remove non-path items from dictionary.
    tupleSize = data.pop('tupleSize')
    _ids = {key: data.pop(key)
                for key in tuple(data.keys()) if id_regex.search(key)}
    #print(f'_ids: {_ids}')
    max_columns = int(tupleSize)  # Use to check a contraint.
    
    # Determine how many columns are present and what they are.
    columns = set()
    for key in data:
        paths = data[key]
        if not paths:
            raise RuntimeError('key with no paths')
        for path in paths:
            comps = path.split(SEP)
            if len(comps) < 2:
                raise RuntimeError('component with no subcomponents')
            columns.add(comps[0])
    
        if len(columns) > max_columns:
            raise RuntimeError('too many columns - conversion aborted')
    
    # Create CSV file.
    with open('converted_json.csv', 'w', newline='') as file:
        writer = csv.DictWriter(file, delimiter=';', restval='~',
                                fieldnames=sorted(columns))
        writer.writeheader()
    
        for key in data:
            row = {}
            for path in data[key]:
                column, *_ = path.split(SEP, maxsplit=1)
                row[column] = path
            writer.writerow(row)
    
    print('Conversion complete')
    

    【讨论】:

    • 我正在尝试使用其他示例运行它,因此延迟接受答案。这正是我所需要的!
    • 我试图正确理解每一行代码。我不明白为什么问题和答案都被否决了。
    • jackw:有人对我的回答投了反对票,并留下了一条冒犯性的评论(现已删除),说他们不喜欢我在第一次向您建议后发布了显示如何解决问题的代码这一事实解决更简单的问题可能是学习 Python 的更好方法。我相当肯定他们也对你的问题投了反对票。这通常发生在仅描述问题但 OP 没有努力自己解决问题的问题上——这是在这里发布的首选问题。
    • jackw:很高兴听到这个消息——我希望是这样。当您获得足够的声望点来投票赞成答案时,我会很感激您这样做。
    • jackw:看起来基本没问题,尽管您可以简单地使用data.keys() 而不是data.items(),因为您不关心关联的值。我还更新了我的答案,以展示如何使用正则表达式来做到这一点,尽管这对于匹配这么简单的模式可能有点过头了。
    猜你喜欢
    • 2015-08-23
    • 2021-06-27
    • 1970-01-01
    • 2019-05-18
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多