设计思路
- 深度优先遍历:采用深度优先遍历(DFS)算法来遍历嵌套的JSON文档。这样可以逐个处理嵌套结构,便于扁平化。
- 路径记录:在遍历过程中,记录每个节点的路径,路径可以用字符串或数组表示,用于生成扁平化后的键。
- 处理循环引用:维护一个已访问节点的集合,当再次遇到已访问节点时,通过特定标识符来处理循环引用。
采用的算法
- 递归DFS:递归函数接受当前节点和路径作为参数。对于对象,遍历其属性;对于数组,遍历其元素。
- 扁平化处理:当遇到叶子节点(非对象和非数组)时,将其值根据路径添加到扁平化结果中。
- 循环引用处理:在进入节点前,检查节点是否在已访问集合中。若存在,用特定标识符替换其值。若不存在,将节点添加到已访问集合。
示例代码(Python)
def flatten_json(nested_json, flatten_dict={}, path=[]):
if isinstance(nested_json, dict):
for key, value in nested_json.items():
new_path = path + [key]
flatten_json(value, flatten_dict, new_path)
elif isinstance(nested_json, list):
for index, value in enumerate(nested_json):
new_path = path + [str(index)]
flatten_json(value, flatten_dict, new_path)
else:
flatten_dict[".".join(map(str, path))] = nested_json
return flatten_dict
def handle_circular_refs(nested_json):
visited = set()
def dfs(node):
if id(node) in visited:
return "<CIRCULAR_REF>"
visited.add(id(node))
if isinstance(node, dict):
result = {}
for key, value in node.items():
result[key] = dfs(value)
return result
elif isinstance(node, list):
return [dfs(value) for value in node]
else:
return node
return dfs(nested_json)
def flatten_with_circular_refs(nested_json):
json_without_circular = handle_circular_refs(nested_json)
return flatten_json(json_without_circular)
如何处理循环引用问题
- 标识符标记:使用一个特殊的字符串(如
<CIRCULAR_REF>
)来标记循环引用的位置。在深度优先遍历过程中,当检测到循环引用时,将其替换为该标识符。
- 记录已访问节点:使用Python的集合(
set
)来记录已访问节点的内存地址(通过id()
函数获取)。每次访问新节点前,检查其内存地址是否在集合中。如果存在,则表明是循环引用。