올바른 항목을 처리하기 위해 키 목록을 통해 액세스하려는 복잡한 사전 구조가 있습니다.
dataDict = {
"a":{
"r": 1,
"s": 2,
"t": 3
},
"b":{
"u": 1,
"v": {
"x": 1,
"y": 2,
"z": 3
},
"w": 3
}
}
maplist = ["a", "r"]
또는
maplist = ["b", "v", "y"]
나는 다음 코드를 작동 시켰지만 누군가 아이디어가 있다면이 작업을 수행하는 더 좋고 효율적인 방법이 있다고 확신합니다.
# Get a given data from a dictionary with position provided as a list
def getFromDict(dataDict, mapList):
for k in mapList: dataDict = dataDict[k]
return dataDict
# Set a given data in a dictionary with position provided as a list
def setInDict(dataDict, mapList, value):
for k in mapList[:-1]: dataDict = dataDict[k]
dataDict[mapList[-1]] = value
답변
reduce()
사전을 통과하는 데 사용하십시오 .
from functools import reduce # forward compatibility for Python 3
import operator
def getFromDict(dataDict, mapList):
return reduce(operator.getitem, mapList, dataDict)
다음에 getFromDict
대한 값을 저장할 위치를 찾기 위해 재사용 하십시오 setInDict()
.
def setInDict(dataDict, mapList, value):
getFromDict(dataDict, mapList[:-1])[mapList[-1]] = value
마지막 요소를 제외한 모든 요소 mapList
는 값을 추가 할 ‘부모’사전을 찾은 다음 마지막 요소를 사용하여 값을 올바른 키로 설정해야합니다.
데모:
>>> getFromDict(dataDict, ["a", "r"])
1
>>> getFromDict(dataDict, ["b", "v", "y"])
2
>>> setInDict(dataDict, ["b", "v", "w"], 4)
>>> import pprint
>>> pprint.pprint(dataDict)
{'a': {'r': 1, 's': 2, 't': 3},
'b': {'u': 1, 'v': {'w': 4, 'x': 1, 'y': 2, 'z': 3}, 'w': 3}}
Python PEP8 스타일 가이드 는 함수의 snake_case 이름을 규정합니다 . 위의 목록 또는 사전과 목록의 혼합에 동일하게 작동하므로 이름은 실제로 다음 get_by_path()
과 같아야합니다 set_by_path()
.
from functools import reduce # forward compatibility for Python 3
import operator
def get_by_path(root, items):
"""Access a nested object in root by item sequence."""
return reduce(operator.getitem, items, root)
def set_by_path(root, items, value):
"""Set a value in a nested object in root by item sequence."""
get_by_path(root, items[:-1])[items[-1]] = value
답변
- 허용 된 솔루션은 python3에서 직접 작동하지 않습니다
from functools import reduce
. - 또한
for
루프 를 사용하는 것이 더 pythonic처럼 보입니다 . Python 3.0의 새로운 기능 에서 인용 한 내용을 참조하십시오 .
제거되었습니다
reduce()
.functools.reduce()
정말로 필요한 경우 사용하십시오 . 그러나 명시 적for
루프가 더 읽기 쉬운 시간의 99 %입니다 . - 다음으로 허용되는 솔루션은 존재하지 않는 중첩 키를 설정하지 않습니다 (을 반환합니다
KeyError
)-솔루션에 대한 @eafit의 답변 참조
따라서 kolergy의 질문에서 제안 된 방법을 사용하여 가치를 얻는 것은 어떻습니까?
def getFromDict(dataDict, mapList):
for k in mapList: dataDict = dataDict[k]
return dataDict
그리고 값을 설정하기위한 @eafit의 답변 코드는 다음과 같습니다.
def nested_set(dic, keys, value):
for key in keys[:-1]:
dic = dic.setdefault(key, {})
dic[keys[-1]] = value
둘 다 파이썬 2와 3에서 바로 작동합니다.
답변
reduce 사용은 영리하지만 부모 키가 중첩 된 사전에 존재하지 않으면 OP의 set 메소드에 문제가있을 수 있습니다. 이것은 내 Google 검색 에서이 주제에 대해 본 첫 번째 게시물이므로 조금 더 좋게 만들고 싶습니다.
( 인덱스 및 값 목록이 제공된 중첩 된 파이썬 사전에 값 설정) 의 set 메소드는 부모 키가 누락 된 경우보다 강력합니다. 그것을 복사하려면 :
def nested_set(dic, keys, value):
for key in keys[:-1]:
dic = dic.setdefault(key, {})
dic[keys[-1]] = value
또한 키 트리를 통과하고 내가 만든 모든 절대 키 경로를 얻는 방법을 사용하는 것이 편리 할 수 있습니다.
def keysInDict(dataDict, parent=[]):
if not isinstance(dataDict, dict):
return [tuple(parent)]
else:
return reduce(list.__add__,
[keysInDict(v,parent+[k]) for k,v in dataDict.items()], [])
이를 사용하는 방법은 다음 코드를 사용하여 중첩 트리를 팬더 DataFrame으로 변환하는 것입니다 (중첩 사전의 모든 리프의 깊이가 같다고 가정).
def dict_to_df(dataDict):
ret = []
for k in keysInDict(dataDict):
v = np.array( getFromDict(dataDict, k), )
v = pd.DataFrame(v)
v.columns = pd.MultiIndex.from_product(list(k) + [v.columns])
ret.append(v)
return reduce(pd.DataFrame.join, ret)
답변
이 라이브러리가 도움이 될 수 있습니다 : https://github.com/akesterson/dpath-python
/ slashed / paths를 통해 사전에 액세스하고 검색하기위한 Python 라이브러리
기본적으로 파일 시스템 인 것처럼 사전을 넘길 수 있습니다.
답변
재귀 함수를 사용하는 것은 어떻습니까?
가치를 얻으려면 :
def getFromDict(dataDict, maplist):
first, rest = maplist[0], maplist[1:]
if rest:
# if `rest` is not empty, run the function recursively
return getFromDict(dataDict[first], rest)
else:
return dataDict[first]
그리고 값을 설정하려면
def setInDict(dataDict, maplist, value):
first, rest = maplist[0], maplist[1:]
if rest:
try:
if not isinstance(dataDict[first], dict):
# if the key is not a dict, then make it a dict
dataDict[first] = {}
except KeyError:
# if key doesn't exist, create one
dataDict[first] = {}
setInDict(dataDict[first], rest, value)
else:
dataDict[first] = value
답변
가져 오기없이 순수한 파이썬 스타일 :
def nested_set(element, value, *keys):
if type(element) is not dict:
raise AttributeError('nested_set() expects dict as first argument.')
if len(keys) < 2:
raise AttributeError('nested_set() expects at least three arguments, not enough given.')
_keys = keys[:-1]
_element = element
for key in _keys:
_element = _element[key]
_element[keys[-1]] = value
example = {"foo": { "bar": { "baz": "ok" } } }
keys = ['foo', 'bar']
nested_set(example, "yay", *keys)
print(example)
산출
{'foo': {'bar': 'yay'}}
답변
키 중 하나가없는 경우 오류를 발생시키지 않으려는 다른 방법 (메인 코드가 중단없이 실행될 수 있음) :
def get_value(self,your_dict,*keys):
curr_dict_ = your_dict
for k in keys:
v = curr_dict.get(k,None)
if v is None:
break
if isinstance(v,dict):
curr_dict = v
return v
이 경우 입력 키가 없으면 None이 반환되고 기본 작업에서 대체 작업을 수행하기위한 검사로 사용될 수 있습니다.