我需要将平面json模式(MySQL查询的结果)转换为带有两个键的分层json结构。我有一个可行的解决方案,使用itertools groupby,但是我对代码进行了更多的转换(比这更复杂),并且我正在寻找一种更好的方法在Python中实现(我使用3.7)。也许我忽略了Python中的一些基本运算符,它们会减少我的代码行,或者那里有一个更好的库。我读过有关具有groupby操作的熊猫的信息,但其重点是数据分析,而不是像这样的数据转换。在Node.js中,我使用了jsonata,所以我想知道python中是否存在用于json转换的更好的库。
要澄清:我想提高开发效率;我不担心运行时效率,因为我的数据集很小。
示例输入显示在下面的代码示例中,并且输出需要类似于以下内容(2级分组依据并重命名元素):
import tkinter as tk
import os
import platform
import pygame
import time
class window(object):
def __init__(self):
self.root = tk.Tk() # Main window
self.root.title("SquareScape")
# self.root.iconbitmap(r'C:\Users\17_es\PycharmProjects\square_puzzle\images\icon.ico')
self.root.configure(background='#9b9b9b')
# Large Frame
self.win_frame = tk.Frame(self.root, width=670, height=520, highlightbackground='#595959', highlightthickness=2)
# menu (left side)
self.menu = tk.Frame(self.win_frame, width=150, height=516, highlightbackground='#595959', highlightthickness=2)
self.menu_label = tk.Label(self.menu, text="Settings", bg='#8a8a8a', font=("Courier", "16", "bold roman"))
self.mute = tk.Button(self.menu, text="XXXX", font="Courier", bg='#bcbcbc', activebackground='#cdcdcd')
tk.Button(self.menu, text="<->", command=lambda: setattr(self, "direction", (-self.direction[0], self.direction[1]))).pack()
tk.Button(self.menu, text="^", command=lambda: setattr(self, "direction", (self.direction[0], -self.direction[1]))).pack()
# pygame
self.pygame_frame = tk.Frame(self.win_frame, width=514, height=514, highlightbackground='#595959', highlightthickness=2)
self.embed = tk.Frame(self.pygame_frame, width=512, height=512,)
# Packing
self.win_frame.pack(expand=True)
self.win_frame.pack_propagate(0)
self.menu.pack(side="left")
self.menu.pack_propagate(0)
self.menu_label.pack(ipadx=60, ipady=2)
self.mute.pack(ipadx=40, ipady=2, pady=5)
self.pygame_frame.pack(side="left")
self.embed.pack()
#This embeds the pygame window
os.environ['SDL_WINDOWID'] = str(self.embed.winfo_id())
system = platform.system()
if system == "Windows":
os.environ['SDL_VIDEODRIVER'] = 'windib'
elif system == "Linux":
os.environ['SDL_VIDEODRIVER'] = 'x11'
self.root.update_idletasks()
#Start pygame
pygame.init()
self.win = pygame.display.set_mode((512, 512))
self.bg_color = (255, 255, 255)
self.win.fill(self.bg_color)
self.pos = 0, 0
self.direction = 10, 10
self.size = 40
self.color = (0, 255, 0)
self.root.after(30, self.update)
self.root.mainloop()
def update(self):
first_move = True
pygame.draw.rect(self.win, self.bg_color, self.pos + (self.size, self.size))
self.pos = self.pos[0] + self.direction[0], self.pos[1] + self.direction[1]
if self.pos[0] < 0 or self.pos[0] > 512 - self.size:
self.direction = -self.direction[0], self.direction[1]
self.pos = self.pos[0] + 2 * self.direction[0], self.pos[1] + self.direction[1]
if self.pos[1] < 0 or self.pos[1] > 512 - self.size:
self.direction = self.direction[0], -self.direction[1]
self.pos = self.pos[0] + self.direction[0], self.pos[1] + 2 * self.direction[1]
pygame.draw.rect(self.win, self.color, self.pos + (self.size, self.size))
pygame.display.flip()
self.root.after(30, self.update)
screen = window()
tk.mainloop()
这是使用itertools提供所需输出的工作代码:
{'researchSubTypeToResolutionCodes': [
{'researchSubTypeCode': None, 'resolutionTypes': [
{'resolutionCode': 999991, 'resolutionSubTypeCodes': [99992, 99993]},
{'resolutionCode': 999995, 'resolutionSubTypeCodes': [99996]}
]
},
{'researchSubTypeCode': 33533, 'resolutionTypes': [
{'resolutionCode': 33726, 'resolutionSubTypeCodes': [33730, 33731, 33732, 33774]},
{'resolutionCode': 33727, 'resolutionSubTypeCodes': [33730, 33731]}
]
},
{'researchSubTypeCode': 33534, 'resolutionTypes': [
{'resolutionCode': 33726, 'resolutionSubTypeCodes': [33730]}
]
}
]}
答案 0 :(得分:1)
我花了两个步骤,但行数却少了很多,从概念上讲,这应该更容易理解。
首先让我们获取所需的数字。这基本上是一个groupby
函数。
为了更好地了解其工作原理,请在for循环的末尾添加print
语句,例如print(temp_dic)
。
temp_dic = dict()
for entry in TEST_QRY_DATA:
if entry["rsch_sub_typ_cd"] not in temp_dic:
temp_dic[entry["rsch_sub_typ_cd"]] = dict()
if entry["resl_cd"] in temp_dic[entry["rsch_sub_typ_cd"]]:
temp_dic[entry["rsch_sub_typ_cd"]][entry["resl_cd"]].append(entry["sub_resl_cd"])
else:
temp_dic[entry["rsch_sub_typ_cd"]][entry["resl_cd"]] = [entry["sub_resl_cd"]]
print(temp_dic)
输出:
{
None: {999991: [99992, 99993], 999995: [99996]},
33533: {33726: [33730, 33731, 33732, 33774], 33727: [33730, 33731]},
33534: {33726: [33730]}
}
现在我们可以添加所需的标签:
final_dict = {'researchSubTypeToResolutionCodes': []}
for researchSubTypeCode, dic in temp_dic.items():
temp_list = [{'resolutionCode': key, 'resolutionSubTypeCodes': val} for key, val in dic.items()]
temp_dic = {'researchSubTypeCode': researchSubTypeCode, 'resolutionTypes': temp_list}
final_dict['researchSubTypeToResolutionCodes'].append(temp_dic)
from pprint import pprint
pprint(final_dict)
输出:
{'researchSubTypeToResolutionCodes': [
{'researchSubTypeCode': None, 'resolutionTypes': [{'resolutionCode': 999991, 'resolutionSubTypeCodes': [99992, 99993]}, {'resolutionCode': 999995, 'resolutionSubTypeCodes': [99996]}]},
{'researchSubTypeCode': 33533, 'resolutionTypes': [{'resolutionCode': 33726, 'resolutionSubTypeCodes': [33730, 33731, 33732, 33774]}, {'resolutionCode': 33727, 'resolutionSubTypeCodes': [33730, 33731]}]},
{'researchSubTypeCode': 33534, 'resolutionTypes': [{'resolutionCode': 33726, 'resolutionSubTypeCodes': [33730]}]}
]}
您也许可以使用example和OrderedDict
和defaultdict
来实现更加动态和递归的解决方案,但要花一些时间才能解决。