生成一个动态嵌套的JSON对象和数组- Python

9

正如问题所述,我一直在尝试生成嵌套的JSON对象。在这种情况下,我使用for循环从字典dic获取数据。以下是代码:

f = open("test_json.txt", 'w')
flag = False
temp = ""
start = "{\n\t\"filename\"" + " : \"" +initial_filename+"\",\n\t\"data\"" +" : " +" [\n"
end = "\n\t]" +"\n}"
f.write(start)
for i, (key,value) in enumerate(dic.iteritems()):
    f.write("{\n\t\"keyword\":"+"\""+str(key)+"\""+",\n")
    f.write("\"term_freq\":"+str(len(value))+",\n")
    f.write("\"lists\":[\n\t")
    for item in value:
        f.write("{\n")
        f.write("\t\t\"occurance\" :"+str(item)+"\n")
        #Check last object
        if value.index(item)+1 == len(value):
            f.write("}\n" 
            f.write("]\n")
        else:
            f.write("},") # close occurrence object
    # Check last item in dic
    if i == len(dic)-1:
        flag = True
    if(flag):
        f.write("}")
    else:
        f.write("},") #close lists object
        flag = False 

#check for flag
f.write("]") #close lists array 
f.write("}")

期望的输出结果是:
{
"filename": "abc.pdf",
"data": [{
    "keyword": "irritation",
    "term_freq": 5,
    "lists": [{
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 2
    }]
}, {
    "keyword": "bomber",
    "lists": [{
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 2
    }],
    "term_freq": 5
}]
}

但是目前我得到的输出如下:
{
"filename": "abc.pdf",
"data": [{
    "keyword": "irritation",
    "term_freq": 5,
    "lists": [{
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 2
    },]                // Here lies the problem "," before array(last element)
}, {
    "keyword": "bomber",
    "lists": [{
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 1
    }, {
        "occurance": 2
    },],                  // Here lies the problem "," before array(last element)
    "term_freq": 5
}]
}

请帮忙,我一直在尝试解决这个问题,但都失败了。请不要标记为重复,因为我已经检查了其他答案,但都没有帮助。
编辑1: 输入基本上是从一个字典dic中取的,其映射类型为<String, List>,例如:"irritation" => [1,3,5,7,8],其中irritation是关键词,映射到一个页面编号列表中。 这基本上是在外部for循环中读取的,其中关键字是key,值是出现该关键字的页面列表。
编辑2:
dic = collections.defaultdict(list) # declaring the variable dictionary
dic[key].append(value) # inserting the values - useless to tell here
for key in dic:
    # Here dic[x] represents list - each value of x
    print key,":",dic[x],"\n" #prints the data in dictionary

1
为什么不使用json.dump,然后在更多数据到达时更新JSON对象呢? - andrea-f
1
有一个很好的简单库叫做 json(无需 pip 安装),使用 import json; print json.dumps(dic) 即可。放松一下吧。 - ZdaR
使用那个库,它是如何解决这个问题的?能否请您分享一段代码片段?@ZdaR - Asif Ali
我已经在上面的评论中分享了所需的代码,它非常简单:import json print json.dumps(dic) - ZdaR
@ZdaR,这是我得到的输出 { "over-dries": [4], "Self": [2], "Cooling": [4] },但这不是我想要的,请理解读取字典和期望输出的问题。 - Asif Ali
显示剩余6条评论
2个回答

9

我认为@andrea-f提出的方案不错,这里还有另一种解决方案:

可以自由选择其中任意一种 :)

import json

dic = {
        "bomber": [1, 2, 3, 4, 5],
        "irritation": [1, 3, 5, 7, 8]
      }

filename = "abc.pdf"

json_dict = {}
data = []

for k, v in dic.iteritems():
  tmp_dict = {}
  tmp_dict["keyword"] = k
  tmp_dict["term_freq"] = len(v)
  tmp_dict["lists"] = [{"occurrance": i} for i in v]
  data.append(tmp_dict)

json_dict["filename"] = filename
json_dict["data"] = data

with open("abc.json", "w") as outfile:
    json.dump(json_dict, outfile, indent=4, sort_keys=True)

这是同样的想法,我首先创建了一个大的json_dict,以便直接保存在JSON中。 我使用with语句保存JSON,避免了捕获exception
此外,如果您需要将来改进您的json输出,请查看json.dumps()文档。 编辑 只是为了好玩,如果您不喜欢tmp变量,您可以在一个一行代码中完成所有的数据for循环 :)
json_dict["data"] = [{"keyword": k, "term_freq": len(v), "lists": [{"occurrance": i} for i in v]} for k, v in dic.iteritems()]

它可能会给出一个最终解决方案,类似于这样不完全可读的东西:
import json

json_dict = {
              "filename": "abc.pdf",
              "data": [{
                        "keyword": k,
                        "term_freq": len(v),
                        "lists": [{"occurrance": i} for i in v]
                       } for k, v in dic.iteritems()]
            }

with open("abc.json", "w") as outfile:
    json.dump(json_dict, outfile, indent=4, sort_keys=True)

编辑 2

看起来您不想将您的json保存为期望的输出,而是希望能够读取它。

实际上,您还可以使用json.dumps()打印您的json。

with open('abc.json', 'r') as handle:
    new_json_dict = json.load(handle)
    print json.dumps(json_dict, indent=4, sort_keys=True)

这里还有一个问题,"filename":在列表末尾打印,因为datadf之前。
为了强制排序,您将需要在字典生成中使用OrderedDict。请注意,使用python 2.X时,语法可能会很丑陋(在我看来)。
这是新的完整解决方案 ;)
import json
from collections import OrderedDict

dic = {
        'bomber': [1, 2, 3, 4, 5],
        'irritation': [1, 3, 5, 7, 8]
      }

json_dict = OrderedDict([
              ('filename', 'abc.pdf'),
              ('data', [ OrderedDict([
                                        ('keyword', k),
                                        ('term_freq', len(v)),
                                        ('lists', [{'occurrance': i} for i in v])
                                     ]) for k, v in dic.iteritems()])
            ])

with open('abc.json', 'w') as outfile:
    json.dump(json_dict, outfile)


# Now to read the orderer json file

with open('abc.json', 'r') as handle:
    new_json_dict = json.load(handle, object_pairs_hook=OrderedDict)
    print json.dumps(json_dict, indent=4)

将产生以下输出:

{
    "filename": "abc.pdf", 
    "data": [
        {
            "keyword": "bomber", 
            "term_freq": 5, 
            "lists": [
                {
                    "occurrance": 1
                }, 
                {
                    "occurrance": 2
                }, 
                {
                    "occurrance": 3
                }, 
                {
                    "occurrance": 4
                }, 
                {
                    "occurrance": 5
                }
            ]
        }, 
        {
            "keyword": "irritation", 
            "term_freq": 5, 
            "lists": [
                {
                    "occurrance": 1
                }, 
                {
                    "occurrance": 3
                }, 
                {
                    "occurrance": 5
                }, 
                {
                    "occurrance": 7
                }, 
                {
                    "occurrance": 8
                }
            ]
        }
    ]
}

但要注意,大多数情况下,最好保存一个普通的 .json 文件,以便跨语言使用。


1
你干得好,老板。 - Asif Ali
@Owl Max,非常抱歉这么晚才来回答您的问题,但是您能否帮助我解决一个类似的问题呢?问题链接为https://dev59.com/pbDla4cB1Zd3GeqP72tw。 - Manas Jani

3
你当前的代码无法运行,因为循环遍历到倒数第二个元素时添加了 },,然后当循环再次运行时,它将标志设置为 false,但最后一次运行时,它添加了一个 ,,因为它认为还会有另一个元素。
如果这是你的字典:a = {"bomber":[1,2,3,4,5]},那么你可以这样做:
import json
file_name = "a_file.json"
file_name_input = "abc.pdf"
new_output = {}
new_output["filename"] = file_name_input

new_data = []
i = 0
for key, val in a.iteritems():
   new_data.append({"keyword":key, "lists":[], "term_freq":len(val)})
   for p in val:
       new_data[i]["lists"].append({"occurrance":p})
   i += 1

new_output['data'] = new_data

然后通过以下方式保存数据:

f = open(file_name, 'w+')
f.write(json.dumps(new_output, indent=4, sort_keys=True, default=unicode))
f.close()

很抱歉,请理解问题,我不是在读取任何类型的JSON文件,我必须从字典Edit 1创建一个JSON输出,而且不仅仅是直接输出,而是按照期望的输出格式进行格式化。 - Asif Ali
你能否按照“期望输出”中的方式重新格式化它?我尝试了一下,但出现了各种错误。如果你能帮忙,我会很感激并接受你的答案。谢谢你的努力。 - Asif Ali
@AsifAli 现在怎么样了? - andrea-f
1
你的代码很好,但我认为@AsifAli的原始想法在for循环中使用enumarate而不是i = 0; i++更符合Pythonic(在我看来)。此外,请查看我的答案中with语句的用例。 - Kruupös

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接