중첩 된 파이썬 사전 및 목록에서 모든 키 발생 찾기
다음과 같은 사전이 있습니다.
{ "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는 동일한 문제에 대해 여러 가지 다른 솔루션을 제공하기 때문에 매우 흥미로 웠습니다. 이 모든 기능을 가져와 복잡한 사전 객체로 테스트했습니다. 테스트에서 두 개의 함수를 가져와야했습니다. 왜냐하면 그들은 많은 실패 결과를 가져야했고, 거의 모든 데이터가 올 때마다 함수가 준비되어야하기 때문에 필수라고 생각하는 값으로 목록이나 딕셔너리를 반환하는 것을 지원하지 않았기 때문 입니다.
그래서 나는 timeit
모듈을 통해 10,000 번의 반복으로 다른 기능을 펌핑하고 다음과 같은 결과를 얻었습니다.
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)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
모든 함수에는 검색 할 동일한 바늘 ( '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 의 함수 와 거의 비슷 하지만, 재귀 중에 문자열이 전달되는 경우 주어진 객체에 iteritems 함수가 있는지 확인하고 있습니다.
def gen_dict_extract(key, var):
if hasattr(var,'iteritems'):
for k, v in var.iteritems():
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']
def find(key, value):
for k, v in value.iteritems():
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.iteritems() 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
하지만 원래 버전이 이해하기 더 쉽다고 생각하므로 그대로 두겠습니다.
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')))
나는 yield from
최상위 목록을 사용 하고 수락 하는 @ hexerei-software의 훌륭한 대답을 반복하고 싶었습니다 .
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)
내가 한 방법은 다음과 같습니다.
이 함수는 중첩 된 사전과 목록을 포함하는 사전을 재귀 적으로 검색합니다. 필드가 발견 될 때마다 값을 포함하는 fields_found라는 목록을 작성합니다. '필드'는 사전과 중첩 된 목록 및 사전에서 찾고있는 키입니다.
def get_recursively (search_dict, field) : "" "중첩 된 목록과 사전이있는 사전을 취합니다. 필드의 키에 대한 모든 사전을 검색합니다. 제공됩니다. "" " fields_found = [] 키의 경우 search_dict.iteritems ()의 값 : 키 == 필드 인 경우 : fields_found.append (값) 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
Another variation, which includes the nested path to the found results (note: this version doesn't consider lists):
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
Here is my stab at it:
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]
'UFO ET IT' 카테고리의 다른 글
번들 식별자 및 푸시 인증서… aps-environment 자격 오류 (0) | 2020.11.07 |
---|---|
Qt : 종횡비를 유지하면서 QPixmap을 포함하는 QLabel 크기 조정 (0) | 2020.11.07 |
firstprivate와 lastprivate는 OpenMP의 private 절과 어떻게 다릅니 까? (0) | 2020.11.07 |
새로 고침과 플러시 (0) | 2020.11.07 |
기본값 유형이 속성 유형과 일치하지 않습니다. (0) | 2020.11.07 |