깊이를 알 수 없는 복잡한 사전을 완전히 탐색하려면 어떻게 해야 합니까?
로부터의 Import »JSON
매우 복잡하고 중첩된 구조를 얻을 수 있습니다.예를 들어 다음과 같습니다.
{u'body': [{u'declarations': [{u'id': {u'name': u'i',
u'type': u'Identifier'},
u'init': {u'type': u'Literal', u'value': 2},
u'type': u'VariableDeclarator'}],
u'kind': u'var',
u'type': u'VariableDeclaration'},
{u'declarations': [{u'id': {u'name': u'j',
u'type': u'Identifier'},
u'init': {u'type': u'Literal', u'value': 4},
u'type': u'VariableDeclarator'}],
u'kind': u'var',
u'type': u'VariableDeclaration'},
{u'declarations': [{u'id': {u'name': u'answer',
u'type': u'Identifier'},
u'init': {u'left': {u'name': u'i',
u'type': u'Identifier'},
u'operator': u'*',
u'right': {u'name': u'j',
u'type': u'Identifier'},
u'type': u'BinaryExpression'},
u'type': u'VariableDeclarator'}],
u'kind': u'var',
u'type': u'VariableDeclaration'}],
u'type': u'Program'}
위와 같은 복잡한 구조물을 걷는 권장 방법은 무엇입니까?
몇 개의 사전이 있는 것을 제외하면, 그 구조가 더 깊이 스며들 수 있기 때문에, 일반적인 해결책이 필요합니다.
사전을 무계층 목록으로 변환하는 데 재귀 생성기를 사용할 수 있습니다.
def dict_generator(indict, pre=None):
pre = pre[:] if pre else []
if isinstance(indict, dict):
for key, value in indict.items():
if isinstance(value, dict):
for d in dict_generator(value, pre + [key]):
yield d
elif isinstance(value, list) or isinstance(value, tuple):
for v in value:
for d in dict_generator(v, pre + [key]):
yield d
else:
yield pre + [key, value]
else:
yield pre + [indict]
다시 돌아오다
[u'body', u'kind', u'var']
[u'init', u'declarations', u'body', u'type', u'Literal']
[u'init', u'declarations', u'body', u'value', 2]
[u'declarations', u'body', u'type', u'VariableDeclarator']
[u'id', u'declarations', u'body', u'type', u'Identifier']
[u'id', u'declarations', u'body', u'name', u'i']
[u'body', u'type', u'VariableDeclaration']
[u'body', u'kind', u'var']
[u'init', u'declarations', u'body', u'type', u'Literal']
[u'init', u'declarations', u'body', u'value', 4]
[u'declarations', u'body', u'type', u'VariableDeclarator']
[u'id', u'declarations', u'body', u'type', u'Identifier']
[u'id', u'declarations', u'body', u'name', u'j']
[u'body', u'type', u'VariableDeclaration']
[u'body', u'kind', u'var']
[u'init', u'declarations', u'body', u'operator', u'*']
[u'right', u'init', u'declarations', u'body', u'type', u'Identifier']
[u'right', u'init', u'declarations', u'body', u'name', u'j']
[u'init', u'declarations', u'body', u'type', u'BinaryExpression']
[u'left', u'init', u'declarations', u'body', u'type', u'Identifier']
[u'left', u'init', u'declarations', u'body', u'name', u'i']
[u'declarations', u'body', u'type', u'VariableDeclarator']
[u'id', u'declarations', u'body', u'type', u'Identifier']
[u'id', u'declarations', u'body', u'name', u'answer']
[u'body', u'type', u'VariableDeclaration']
[u'type', u'Program']
사용법을 walk
사전을 가져온 다음 해당 요소를 재귀적으로 이동하는 함수입니다.다음과 같이 합니다.
def walk(node):
for key, item in node.items():
if item is a collection:
walk(item)
else:
It is a leaf, do your thing
요소를 검색하거나 특정 기준을 통과한 여러 요소를 쿼리하려면 jsonpath 모듈을 참조하십시오.
를 직접 쓰는 할 수 .json
★★★★★★ 。
특히 커스텀클래스에 속하는 오브젝트를 json으로 인코딩할 필요가 있는 경우 이 방법을 권장합니다.json 문자열 표현에서도 수행할 수 있는 작업을 수행해야 하는 경우 JSONEncoder().iterencode를 반복하는 것도 고려하십시오.
양쪽의 레퍼런스는 http://docs.python.org/2/library/json.html#encoders-and-decoders 입니다.
있는 는, 「」를 할 수 .parse
중첩된 컨테이너를 사용자 지정 유형의 개체 트리로 변환하는 함수입니다.그런 다음 이러한 커스텀오브젝트의 메서드를 사용하여 데이터에 대해 필요한 작업을 수행합니다.
, 데이터 때, 를 들면 '아까보다'를 만들 수 .Program
,VariableDeclaration
,VariableDeclarator
,Identifier
,Literal
★★★★★★★★★★★★★★★★★」BinaryExpression
. 파서는 이렇게 해요.
def parse(d):
t = d[u"type"]
if t == u"Program":
body = [parse(block) for block in d[u"body"]]
return Program(body)
else if t == u"VariableDeclaration":
kind = d[u"kind"]
declarations = [parse(declaration) for declaration in d[u"declarations"]]
return VariableDeclaration(kind, declarations)
else if t == u"VariableDeclarator":
id = parse(d[u"id"])
init = parse(d[u"init"])
return VariableDeclarator(id, init)
else if t == u"Identifier":
return Identifier(d[u"name"])
else if t == u"Literal":
return Literal(d[u"value"])
else if t == u"BinaryExpression":
operator = d[u"operator"]
left = parse(d[u"left"])
right = parse(d[u"right"])
return BinaryExpression(operator, left, right)
else:
raise ValueError("Invalid data structure.")
도움이 될 수 있습니다.
def walk(d):
global path
for k,v in d.items():
if isinstance(v, str) or isinstance(v, int) or isinstance(v, float):
path.append(k)
print "{}={}".format(".".join(path), v)
path.pop()
elif v is None:
path.append(k)
## do something special
path.pop()
elif isinstance(v, dict):
path.append(k)
walk(v)
path.pop()
else:
print "###Type {} not recognized: {}.{}={}".format(type(v), ".".join(path),k, v)
mydict = {'Other': {'Stuff': {'Here': {'Key': 'Value'}}}, 'root1': {'address': {'country': 'Brazil', 'city': 'Sao', 'x': 'Pinheiros'}, 'surname': 'Fabiano', 'name': 'Silos', 'height': 1.9}, 'root2': {'address': {'country': 'Brazil', 'detail': {'neighbourhood': 'Central'}, 'city': 'Recife'}, 'surname': 'My', 'name': 'Friend', 'height': 1.78}}
path = []
walk(mydict)
다음과 같은 출력이 생성됩니다.
Other.Stuff.Here.Key=Value
root1.height=1.9
root1.surname=Fabiano
root1.name=Silos
root1.address.country=Brazil
root1.address.x=Pinheiros
root1.address.city=Sao
root2.height=1.78
root2.surname=My
root2.name=Friend
root2.address.country=Brazil
root2.address.detail.neighbourhood=Central
root2.address.city=Recife
JSON 구조 전체를 이동하거나 매핑하려면 다음 코드를 사용할 수 있습니다.
def walk(node, key):
if type(node) is dict:
return {k: walk(v, k) for k, v in node.items()}
elif type(node) is list:
return [walk(x, key) for x in node]
else:
return YourFunction(node, key)
def YourFunction(node, key):
if key == "yourTargetField": # for example, you want to modify yourTargetField
return "Modified Value"
return node # return existing value
이것은 전체 json 구조를 통과하고 모든 리프(엔드포인트 키와 값의 쌍)를 함수를 통해 실행합니다.함수는 수정된 값을 반환합니다.전체 걷기 기능은 처리된 새 개체를 순서대로 제공합니다.
받아들여진 답변이 유효하지만, 네스트된 배열의 수치 인덱스를 포함한 완전한 순서 패스를 필요로 하는 경우는, 다음의 약간의 변화가 유효합니다.
def dict_generator(indict, pre=None):
pre = pre[:] if pre else []
if isinstance(indict, dict):
for key, value in indict.items():
if isinstance(value, dict):
for d in dict_generator(value, pre + [key]):
yield d
elif isinstance(value, list) or isinstance(value, tuple):
for k,v in enumerate(value):
for d in dict_generator(v, pre + [key] + [k]):
yield d
else:
yield pre + [key, value]
else:
yield indict
위의 솔루션에 대한 추가 사항(목록을 포함한 json을 위해)
#!/usr/bin/env python
import json
def walk(d):
global path
for k,v in d.items():
if isinstance(v, str) or isinstance(v, int) or isinstance(v, float):
path.append(k)
print("{}={}".format(".".join(path), v))
path.pop()
elif v is None:
path.append(k)
# do something special
path.pop()
elif isinstance(v, list):
path.append(k)
for v_int in v:
walk(v_int)
path.pop()
elif isinstance(v, dict):
path.append(k)
walk(v)
path.pop()
else:
print("###Type {} not recognized: {}.{}={}".format(type(v), ".".join(path),k, v))
with open('abc.json') as f:
myjson = json.load(f)
path = []
walk(myjson)
보다 유연한 버전은 다음과 같습니다.
def walktree(tree, at=lambda node: not isinstance(node, dict), prefix=(),
flattennode=lambda node:isinstance(node, (list, tuple, set))):
"""
Traverse a tree, and return a iterator of the paths from the root nodes to the leaf nodes.
tree: like '{'a':{'b':1,'c':2}}'
at: a bool function or a int indicates levels num to go down. walktree(tree, at=1) equivalent to tree.items()
flattennode: a bool function to decide whether to iterate at node value
"""
if isinstance(at, int):
isleaf_ = at == 0
isleaf = lambda v: isleaf_
at = at - 1
else:
isleaf = at
if isleaf(tree):
if not flattennode(tree):
yield (*prefix, tree)
else:
for v in tree:
yield from walktree(v, at, prefix, flattennode=flattennode)
else:
for k,v in tree.items():
yield from walktree(v, at, (*prefix, k), flattennode=flattennode)
사용방법:
> list(walktree({'a':{'b':[0,1],'c':2}, 'd':3}))
[('a', 'b', 0), ('a', 'b', 1), ('a', 'c', 2), ('d', 3)]
> list(walktree({'a':{'b':[0,1],'c':2}, 'd':3}, flattennode=lambda e:False))
[('a', 'b', [0, 1]), ('a', 'c', 2), ('d', 3)]
> list(walktree({'a':{'b':[0,1],'c':2}, 'd':3}, at=1))
[('a', {'b': [0, 1], 'c': 2}), ('d', 3)]
> list(walktree({'a':{'b':[0,{1:9,9:1}],'c':2}, 'd':3}))
[('a', 'b', 0), ('a', 'b', 1, 9), ('a', 'b', 9, 1), ('a', 'c', 2), ('d', 3)]
> list(walktree([1,2,3,[4,5]]))
[(1,), (2,), (3,), (4,), (5,)]
승인된 솔루션의 약간 개선된 버전입니다.Python3를 사용하고 있다면(사용하시길 바랍니다) Python 3.3에서 도입된 구문을 사용할 수 있습니다.또한.isinstance
두 번째 인수는 태플을 받아들일 수 있습니다.
def dict_generator(adict, pre=None):
pre = pre[:] if pre else []
if isinstance(adict, dict):
for key, value in adict.items():
if isinstance(value, dict):
yield from dict_generator(value, pre + [key])
elif isinstance(value, (list, tuple)):
for v in value:
yield from dict_generator(v, pre + [key])
else:
yield pre + [key, value]
else:
yield pre + [adict]
반복 버전(제너레이터를 사용하는 경우 매우 유사):
def flatten(adict):
stack = [[adict, []]]
while stack:
d, pre = stack.pop()
if isinstance(d, dict):
for key, value in d.items():
if isinstance(value, dict):
stack.append([value, pre + [key]])
elif isinstance(value, (list, tuple)):
for v in value:
stack.append([v, pre + [key]])
else:
print(pre + [key, value])
else:
print(pre + [d])
언급URL : https://stackoverflow.com/questions/12507206/how-to-completely-traverse-a-complex-dictionary-of-unknown-depth
'it-source' 카테고리의 다른 글
'this'에는 형식 주석이 없으므로 암시적으로 형식 'any'가 있습니다. (0) | 2023.03.22 |
---|---|
반응의 onClick 핸들러를 사용하여 href "새 탭에서 열기" 유지 (0) | 2023.03.22 |
.getJ에서 인코딩을 설정하는 방법SON jQuery (0) | 2023.03.17 |
visualvm 및 JMX를 사용한 리모트 감시 (0) | 2023.03.17 |
Angular를 연장하는 권장 방법은 무엇입니까?JS 컨트롤러? (0) | 2023.03.17 |