중첩된 사전 및 목록에서 키의 모든 항목 찾기
나는 다음과 같은 사전을 가지고 있습니다.
{
"id": "abcde",
"key1": "blah",
"key2": "blah blah",
"nestedlist": [
{
"id": "qwerty",
"nestednestedlist": [
{
"id": "xyz",
"keyA": "blah blah blah"
},
{
"id": "fghi",
"keyZ": "blah blah blah"
}
],
"anothernestednestedlist": [
{
"id": "asdf",
"keyQ": "blah blah"
},
{
"id": "yuiop",
"keyW": "blah"
}
]
}
]
}
기본적으로 임의 깊이의 목록, 사전 및 문자열이 중첩된 사전입니다.
모든 "id" 키의 값을 추출하는 가장 좋은 방법은 무엇입니까?"/id"와 같은 XPath 쿼리에 해당하는 값을 얻고 싶습니다."id"의 값은 항상 문자열입니다.
제 예에서 제가 필요로 하는 출력은 기본적으로 다음과 같습니다.
["abcde", "qwerty", "xyz", "fghi", "asdf", "yuiop"]
순서는 중요하지 않습니다.
저는 이 Q/A가 동일한 문제에 대해 여러 가지 다른 해결책을 제공하기 때문에 매우 흥미로웠습니다.저는 이 모든 기능을 가지고 복잡한 사전 객체로 테스트했습니다.저는 두 가지 기능을 테스트에서 제외해야 했습니다. 왜냐하면 그들은 많은 실패한 결과를 가지고 있었고 목록이나 딕트를 값으로 반환하는 것을 지원하지 않았기 때문입니다. 왜냐하면 그들은 거의 모든 데이터에 대해 기능이 준비되어야 하기 때문에 필수적인 것이라고 생각합니다.
그래서 저는 다른 기능들을 100,000번의 반복으로 펌핑했습니다.timeit
모듈 및 출력 결과는 다음과 같습니다.
0.11 usec/pass on gen_dict_extract(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
6.03 usec/pass on find_all_items(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0.15 usec/pass on findkeys(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1.79 usec/pass on get_recursively(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0.14 usec/pass on find(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0.36 usec/pass on dict_extract(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
모든 함수는 검색할 동일한 Needle('logging')과 동일한 사전 개체를 가지고 있으며 다음과 같이 구성됩니다.
o = { 'temparature': '50',
'logging': {
'handlers': {
'console': {
'formatter': 'simple',
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stdout',
'level': 'DEBUG'
}
},
'loggers': {
'simpleExample': {
'handlers': ['console'],
'propagate': 'no',
'level': 'INFO'
},
'root': {
'handlers': ['console'],
'level': 'DEBUG'
}
},
'version': '1',
'formatters': {
'simple': {
'datefmt': "'%Y-%m-%d %H:%M:%S'",
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
}
}
},
'treatment': {'second': 5, 'last': 4, 'first': 4},
'treatment_plan': [[4, 5, 4], [4, 5, 4], [5, 5, 5]]
}
모든 기능이 동일한 결과를 제공했지만, 시간 차이는 극적입니다!함수gen_dict_extract(k,o)
내 기능은 여기 있는 기능에서 조정된 것입니까, 사실 그것은 거의 비슷합니다.find
재귀 중에 문자열이 전달될 경우를 대비하여 주어진 객체에 반복 항목 함수가 있는지 확인하는 것이 주요 차이점인 Alfe의 함수:
# python 2
def gen_dict_extract(key, var):
if hasattr(var,'iteritems'): # hasattr(var,'items') for python 3
for k, v in var.iteritems(): # var.items() for python 3
if k == key:
yield v
if isinstance(v, dict):
for result in gen_dict_extract(key, v):
yield result
elif isinstance(v, list):
for d in v:
for result in gen_dict_extract(key, d):
yield result
이 변종은 여기서 가장 빠르고 안전한 기능입니다.find_all_items
믿을 수 없을 정도로 느리고 두 번째로 느립니다.get_recursivley
제외하고 나머지는dict_extract
서로 가깝습니다.함수fun
그리고.keyHole
문자열을 찾고 있는 경우에만 작동합니다.
여기서 흥미로운 학습 측면:)
d = { "id" : "abcde",
"key1" : "blah",
"key2" : "blah blah",
"nestedlist" : [
{ "id" : "qwerty",
"nestednestedlist" : [
{ "id" : "xyz", "keyA" : "blah blah blah" },
{ "id" : "fghi", "keyZ" : "blah blah blah" }],
"anothernestednestedlist" : [
{ "id" : "asdf", "keyQ" : "blah blah" },
{ "id" : "yuiop", "keyW" : "blah" }] } ] }
def fun(d):
if 'id' in d:
yield d['id']
for k in d:
if isinstance(d[k], list):
for i in d[k]:
for j in fun(i):
yield j
>>> list(fun(d))
['abcde', 'qwerty', 'xyz', 'fghi', 'asdf', 'yuiop']
d = { "id" : "abcde",
"key1" : "blah",
"key2" : "blah blah",
"nestedlist" : [
{ "id" : "qwerty",
"nestednestedlist" : [
{ "id" : "xyz", "keyA" : "blah blah blah" },
{ "id" : "fghi", "keyZ" : "blah blah blah" }],
"anothernestednestedlist" : [
{ "id" : "asdf", "keyQ" : "blah blah" },
{ "id" : "yuiop", "keyW" : "blah" }] } ] }
def findkeys(node, kv):
if isinstance(node, list):
for i in node:
for x in findkeys(i, kv):
yield x
elif isinstance(node, dict):
if kv in node:
yield node[kv]
for j in node.values():
for x in findkeys(j, kv):
yield x
print(list(findkeys(d, 'id')))
def find(key, value):
for k, v in value.items():
if k == key:
yield v
elif isinstance(v, dict):
for result in find(key, v):
yield result
elif isinstance(v, list):
for d in v:
for result in find(key, d):
yield result
편집: @Anthon은 이것이 직접 중첩된 목록에 대해 작동하지 않는다는 것을 알아차렸습니다.입력에 이 정보가 있으면 다음을 사용할 수 있습니다.
def find(key, value):
for k, v in (value.items() if isinstance(value, dict) else
enumerate(value) if isinstance(value, list) else []):
if k == key:
yield v
elif isinstance(v, (dict, list)):
for result in find(key, v):
yield result
하지만 원래 버전이 더 이해하기 쉬울 것 같아서 그대로 두겠습니다.
pip install nested-lookup
원하는 작업을 정확하게 수행합니다.
document = [ { 'taco' : 42 } , { 'salsa' : [ { 'burrito' : { 'taco' : 69 } } ] } ]
>>> print(nested_lookup('taco', document))
[42, 69]
저는 단지 @hexerei-software의 훌륭한 답변을 반복하고 싶었습니다.yield from
최상위 목록을 수락합니다.
def gen_dict_extract(var, key):
if isinstance(var, dict):
for k, v in var.items():
if k == key:
yield v
if isinstance(v, (dict, list)):
yield from gen_dict_extract(v, key)
elif isinstance(var, list):
for d in var:
yield from gen_dict_extract(d, key)
발견된 결과에 대한 중첩 경로를 포함하는 다른 변형입니다(참고: 이 버전은 목록을 고려하지 않음).
def find_all_items(obj, key, keys=None):
"""
Example of use:
d = {'a': 1, 'b': 2, 'c': {'a': 3, 'd': 4, 'e': {'a': 9, 'b': 3}, 'j': {'c': 4}}}
for k, v in find_all_items(d, 'a'):
print "* {} = {} *".format('->'.join(k), v)
"""
ret = []
if not keys:
keys = []
if key in obj:
out_keys = keys + [key]
ret.append((out_keys, obj[key]))
for k, v in obj.items():
if isinstance(v, dict):
found_items = find_all_items(v, key, keys=(keys+[k]))
ret += found_items
return ret
이 함수는 중첩된 사전과 목록을 포함하는 사전을 재귀적으로 검색합니다.필드가 발견될 때마다 값을 포함하는 fields_found라는 목록을 작성합니다.'필드'는 제가 사전과 중첩된 목록 및 사전에서 찾고 있는 키입니다.
def get_recursively(search_dict, field):
"""Takes a dict with nested lists and dicts,
and searches all dicts for a key of the field
provided.
"""
fields_found = []
for key, value in search_dict.iteritems():
if key == field:
fields_found.append(value)
elif isinstance(value, dict):
results = get_recursively(value, field)
for result in results:
fields_found.append(result)
elif isinstance(value, list):
for item in value:
if isinstance(item, dict):
more_results = get_recursively(item, field)
for another_result in more_results:
fields_found.append(another_result)
return fields_found
즉시 사용할 수 있도록 여기에 솔루션을 게시할 수 없었기 때문에 좀 더 유연한 내용을 작성하고자 했습니다.
아래의 재귀 함수를 사용하면 임의로 깊게 중첩된 사전 및 목록 집합에서 지정된 키에 대해 일부 정규식 패턴을 충족하는 모든 값을 수집할 수 있습니다.
import re
def search(dictionary, search_pattern, output=None):
"""
Search nested dictionaries and lists using a regex search
pattern to match a key and return the corresponding value(s).
"""
if output is None:
output = []
pattern = re.compile(search_pattern)
for k, v in dictionary.items():
pattern_found = pattern.search(k)
if not pattern_found:
if isinstance(v, list):
for item in v:
if isinstance(item, dict):
search(item, search_pattern, output)
if isinstance(v, dict):
search(v, search_pattern, output)
else:
if pattern_found:
output.append(v)
return output
특정 용어를 검색하려면 항상 검색 패턴을 다음과 같이 만들 수 있습니다.r'\bsome_term\b'
.
여기 제가 시도한 것이 있습니다.
def keyHole(k2b,o):
# print "Checking for %s in "%k2b,o
if isinstance(o, dict):
for k, v in o.iteritems():
if k == k2b and not hasattr(v, '__iter__'): yield v
else:
for r in keyHole(k2b,v): yield r
elif hasattr(o, '__iter__'):
for r in [ keyHole(k2b,i) for i in o ]:
for r2 in r: yield r2
return
>>> findMe = {'Me':{'a':2,'Me':'bop'},'z':{'Me':4}}
>>> keyHole('Me',findMe)
<generator object keyHole at 0x105eccb90>
>>> [ x for x in keyHole('Me',findMe) ]
['bop', 4]
@hexerei 소프트웨어의 답변과 @bruno-bronosky의 의견에 따라 키 목록/세트를 반복할 경우:
def gen_dict_extract(var, keys):
for key in keys:
if hasattr(var, 'items'):
for k, v in var.items():
if k == key:
yield v
if isinstance(v, dict):
for result in gen_dict_extract([key], v):
yield result
elif isinstance(v, list):
for d in v:
for result in gen_dict_extract([key], d):
yield result
문자열 키 대신 단일 요소([key]})가 있는 목록을 전달합니다.
Python에는 최대 재귀 깊이가 있기 때문에 임의 크기에 대해 반복적인 접근 방식을 구현하는 것을 고려합니다.
def get_ids(data: Dict, key: str) -> List:
stack = [data]
result = []
while stack:
elem = stack.pop()
if isinstance(elem, dict):
for k, v in elem.items():
if k == key:
result.append(v)
if isinstance(elem, (list, dict)):
stack.append(v)
elif isinstance(elem, list):
for obj in elem:
stack.append(obj)
return result
언급URL : https://stackoverflow.com/questions/9807634/find-all-occurrences-of-a-key-in-nested-dictionaries-and-lists
'programing' 카테고리의 다른 글
로드 시 색상이 지정된 이미지에 잘못된 색상을 부여하는 CV 열기 (0) | 2023.09.01 |
---|---|
"실행 중인 스크립트가 이 시스템에서 비활성화됨"을 수정하는 방법은 무엇입니까? (0) | 2023.09.01 |
TSQL에서 날짜로부터 분기별 캘린더를 가져오는 방법 (0) | 2023.09.01 |
jQuery의 $.get()가 신뢰할 수 없는 URL에서 호출해도 안전합니까? (0) | 2023.09.01 |
산점도:오른쪽의 lib-axis (0) | 2023.09.01 |