programing

키 목록을 통해 중첩된 사전 항목에 액세스하시겠습니까?

padding 2023. 4. 13. 20:38
반응형

키 목록을 통해 중첩된 사전 항목에 액세스하시겠습니까?

저는 복잡한 사전 구조를 가지고 있으며 올바른 항목을 다루기 위해 키 목록을 통해 접근하고 싶습니다.

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)

「」를 재이용합니다.getFromDictsetInDict():

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

그리고 완성을 위해 키를 삭제하는 기능:

def del_by_path(root, items):
    """Delete a key-value in a nested object in root by item sequence."""
    del get_by_path(root, items[:-1])[items[-1]]

더 피조어적인 것 같아요.for루프. "What's New In Python 3.0"의 인용문을 참조하십시오.

되었습니다.reduce()을 사용하다functools.reduce()로 명시되어 for루프가 읽기 쉬워집니다.

def nested_get(dic, keys):    
    for key in keys:
        dic = dic[key]
    return dic

def nested_set(dic, keys, value):
    for key in keys[:-1]:
        dic = dic.setdefault(key, {})
    dic[keys[-1]] = value

def nested_del(dic, keys):
    for key in keys[:-1]:
        dic = dic[key]
    del dic[keys[-1]]

하지 않는 것에 주의해 주세요(에 의해, 「네스트 키」가 발생합니다).KeyError위의 방법을 사용하면 존재하지 않는 노드가 생성됩니다.

이 코드는 Python 2와 3 모두에서 작동합니다.

reduce를 사용하는 것은 현명하지만 부모 키가 중첩된 사전에 존재하지 않으면 OP의 설정 메서드에 문제가 있을 수 있습니다.구글 검색에서 처음 본 SO 게시물이기 때문에 조금 더 개선하고 싶습니다.

(인덱스값 목록이 주어진 중첩된 python 사전에서 값 설정)의 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 xpath를 통해 사전에 액세스하고 검색할 수 있는 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

아웃 ★★★★NestedDict(내가 작성자)라는 명령어 패키지에서 원하는 대로 동작합니다.

from ndicts import NestedDict

data_dict = {
    "a":{
        "r": 1,
        "s": 2,
        "t": 3
        },
    "b":{
        "u": 1,
        "v": {
            "x": 1,
            "y": 2,
            "z": 3
        },
        "w": 3
        }
}  

nd = NestedDict(data_dict)

이제 쉼표로 구분된 값을 사용하여 키에 액세스할 수 있습니다.

>>> nd["a", "r"]
    1
>>> nd["b", "v"]
    {"x": 1, "y": 2, "z": 3}

재귀로 해결:

def get(d,l):
    if len(l)==1: return d[l[0]]
    return get(d[l[0]],l[1:])

예를 들어 다음과 같습니다.

dataDict = {
    "a":{
        "r": 1,
        "s": 2,
        "t": 3
        },
    "b":{
        "u": 1,
        "v": {
            "x": 1,
            "y": 2,
            "z": 3
        },
        "w": 3
        }
}
maplist1 = ["a", "r"]
maplist2 = ["b", "v", "y"]
print(get(dataDict, maplist1)) # 1
print(get(dataDict, maplist2)) # 2

것이 을 한 번하게 한 다음 요?b:v:y

def flatten(mydict,sep = ':'):
  new_dict = {}
  for key,value in mydict.items():
    if isinstance(value,dict):
      _dict = {sep.join([key, _key]):_value for _key, _value in flatten(value).items()}
      new_dict.update(_dict)
    else:
      new_dict[key]=value
  return new_dict

dataDict = {
"a":{
    "r": 1,
    "s": 2,
    "t": 3
    },
"b":{
    "u": 1,
    "v": {
        "x": 1,
        "y": 2,
        "z": 3
    },
    "w": 3
    }
}    

flat_dict = flatten(dataDict)
print flat_dict
{'b:w': 3, 'b:u': 1, 'b:v:y': 2, 'b:v:x': 1, 'b:v:z': 3, 'a:r': 1, 'a:s': 2, 'a:t': 3}

간단하게 수 있습니다.flat_dict['b:v:y'] 그 you you you 를 얻을 수 .1.

또한 각 검색에서 사전을 이동하는 대신 사전을 평평하게 만들고 출력을 저장함으로써 이 속도를 높일 수 있습니다. 콜드 스타트로부터의 검색이 평평한 사전을 로드하고 통과 없이 키/값 검색을 수행하는 것을 의미합니다.

pydash를 사용할 수 있습니다.

import pydash as _

_.get(dataDict, ["b", "v", "y"], default='Default')

https://pydash.readthedocs.io/en/latest/api.html

Import 없이 Pure Python 스타일:

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이 반환됩니다.이 키는 다른 작업을 수행하기 위한 메인코드 체크로 사용할 수 있습니다.

네스트된 Atribute를 설정 및 취득하기 위한 2가지 정적 메서드가 있는 경우, 이러한 답변은 만족할 수 있습니다.이러한 솔루션은 네스트된 트리를 사용하는 것보다 훨씬 우수합니다.https://gist.github.com/hrldcpr/2012250

제 실장은 이렇습니다.

사용방법:

하려면 , 「」를 합니다.sattr(my_dict, 1, 2, 3, 5) is equal to my_dict[1][2][3][4]=5

하려면 , 「」를 합니다.gattr(my_dict, 1, 2)

def gattr(d, *attrs):
    """
    This method receives a dict and list of attributes to return the innermost value of the give dict       
    """
    try:
        for at in attrs:
            d = d[at]
        return d
    except(KeyError, TypeError):
        return None


def sattr(d, *attrs):
    """
    Adds "val" to dict in the hierarchy mentioned via *attrs
    For ex:
    sattr(animals, "cat", "leg","fingers", 4) is equivalent to animals["cat"]["leg"]["fingers"]=4
    This method creates necessary objects until it reaches the final depth
    This behaviour is also known as autovivification and plenty of implementation are around
    This implementation addresses the corner case of replacing existing primitives
    https://gist.github.com/hrldcpr/2012250#gistcomment-1779319
    """
    for attr in attrs[:-2]:
        if type(d.get(attr)) is not dict:
            d[attr] = {}
        d = d[attr]
    d[attrs[-2]] = attrs[-1]

중첩된 사전 또는 목록에서 필드 값을 가져오는 다목적 단순 함수:

def key_chain(data, *args, default=None):
    for key in args:
        if isinstance(data, dict):
            data = data.get(key, default)
        elif isinstance(data, (list, tuple)) and isinstance(key, int):
            try:
                data = data[key]
            except IndexError:
                return default
        else:
            return default
    return data

누락된 키가 있으면 기본값을 반환하고 목록 및 튜플에 대해 정수 키를 지원합니다.당신의 경우에는 이렇게 말할 수 있습니다.

key_chain(dataDict, *maplist)

또는

key_chain(dataDict, "b", "v", "y")

더 많은 사용 예: https://gist.github.com/yaznahar/26bd3442467aff5d126d345cca0efcad

네스트 리스트나 딕트를 포함한 임의의 json을 조작해, 무효인 룩업 패스를 적절히 처리할 수 있는 기능도 원한다면, 다음의 솔루션을 참조해 주세요.

from functools import reduce


def get_furthest(s, path):
    '''
    Gets the furthest value along a given key path in a subscriptable structure.

    subscriptable, list -> any
    :param s: the subscriptable structure to examine
    :param path: the lookup path to follow
    :return: a tuple of the value at the furthest valid key, and whether the full path is valid
    '''

    def step_key(acc, key):
        s = acc[0]
        if isinstance(s, str):
            return (s, False)
        try:
            return (s[key], acc[1])
        except LookupError:
            return (s, False)

    return reduce(step_key, path, (s, True))


def get_val(s, path):
    val, successful = get_furthest(s, path)
    if successful:
        return val
    else:
        raise LookupError('Invalid lookup path: {}'.format(path))


def set_val(s, path, value):
    get_val(s, path[:-1])[path[-1]] = value

모든 인덱스를 두 번 처리하지 않고 체크 후 dict 요소를 설정하는 것은 어떻습니까?

솔루션:

def nested_yield(nested, keys_list):
    """
    Get current nested data by send(None) method. Allows change it to Value by calling send(Value) next time
    :param nested: list or dict of lists or dicts
    :param keys_list: list of indexes/keys
    """
    if not len(keys_list):  # assign to 1st level list
        if isinstance(nested, list):
            while True:
                nested[:] = yield nested
        else:
            raise IndexError('Only lists can take element without key')


    last_key = keys_list.pop()
    for key in keys_list:
        nested = nested[key]

    while True:
        try:
            nested[last_key] = yield nested[last_key]
        except IndexError as e:
            print('no index {} in {}'.format(last_key, nested))
            yield None

워크플로우 예:

ny = nested_yield(nested_dict, nested_address)
data_element = ny.send(None)
if data_element:
    # process element
    ...
else:
    # extend/update nested data
    ny.send(new_data_element)
    ...
ny.close()

시험

>>> cfg= {'Options': [[1,[0]],[2,[4,[8,16]]],[3,[9]]]}
    ny = nested_yield(cfg, ['Options',1,1,1])
    ny.send(None)
[8, 16]
>>> ny.send('Hello!')
'Hello!'
>>> cfg
{'Options': [[1, [0]], [2, [4, 'Hello!']], [3, [9]]]}
>>> ny.close()

파티에 늦었지만, 만약을 위해 글을 올리는 것이 미래에 도움이 될 수도 있습니다.제 사용 예에서는 다음과 같은 기능이 가장 잘 작동했습니다.사전에서 모든 데이터 유형을 꺼내는 데 사용됩니다.

dict는 우리의 가치를 담은 사전이다.

list는 우리의 가치를 향한 "단계" 목록입니다.

def getnestedvalue(dict, list):

    length = len(list)
    try:
        for depth, key in enumerate(list):
            if depth == length - 1:
                output = dict[key]
                return output
            dict = dict[key]
    except (KeyError, TypeError):
        return None

    return None

단순한 재귀 함수를 사용하는 것이 좋습니다.

def get_value_by_path(data, maplist):
    if not maplist:
        return data
    for key in maplist:
        if key in data:
            return get_value_by_path(data[key], maplist[1:])

문자열을 연결하는 방법:

def get_sub_object_from_path(dict_name, map_list):
    for i in map_list:
        _string = "['%s']" % i
        dict_name += _string
    value = eval(dict_name)
    return value
#Sample:
_dict = {'new': 'person', 'time': {'for': 'one'}}
map_list = ['time', 'for']
print get_sub_object_from_path("_dict",map_list)
#Output:
#one

@DomTomCat 등의 접근 방식을 확장하면 이러한 기능(즉, 입력에 영향을 주지 않고 딥카피를 통해 수정된 데이터를 반환) 세터와 매퍼가 네스트에 대해 작동합니다.dict그리고.list.

세터:

def set_at_path(data0, keys, value):
    data = deepcopy(data0)
    if len(keys)>1:
        if isinstance(data,dict):
            return {k:(set_by_path(v,keys[1:],value) if k==keys[0] else v) for k,v in data.items()}
        if isinstance(data,list):
            return [set_by_path(x[1],keys[1:],value) if x[0]==keys[0] else x[1] for x in enumerate(data)]
    else:
        data[keys[-1]]=value
        return data

매퍼:

def map_at_path(data0, keys, f):
    data = deepcopy(data0)
    if len(keys)>1:
        if isinstance(data,dict):
            return {k:(map_at_path(v,keys[1:],f) if k==keys[0] else v) for k,v in data.items()}
        if isinstance(data,list):
            return [map_at_path(x[1],keys[1:],f) if x[0]==keys[0] else x[1] for x in enumerate(data)]
    else:
        data[keys[-1]]=f(data[keys[-1]])
        return data

나는 이것을 사용한다.

def get_dictionary_value(dictionary_temp, variable_dictionary_keys):
     try:
          if(len(variable_dictionary_keys) == 0):
               return str(dictionary_temp)

          variable_dictionary_key = variable_dictionary_keys[0]
          variable_dictionary_keys.remove(variable_dictionary_key)

          return get_dictionary_value(dictionary_temp[variable_dictionary_key] , variable_dictionary_keys)

     except Exception as variable_exception:
          logging.error(variable_exception)
 
          return ''

를 사용할 수 있습니다.evalpython으로 기능합니다.

def nested_parse(nest, map_list):
    nestq = "nest['" + "']['".join(map_list) + "']"
    return eval(nestq, {'__builtins__':None}, {'nest':nest})

설명.

예제 쿼리의 경우:maplist = ["b", "v", "y"]

nestq될 것이다"nest['b']['v']['y']"어디에nest는 네스트된 딕셔너리입니다.

evalbuiltin 함수는 지정된 문자열을 실행합니다.단, 다음 명령어를 사용하여 발생할 수 있는 취약성에 주의하는 것이 중요합니다.eval기능.토론은 다음 URL에서 확인할 수 있습니다.

  1. https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
  2. https://www.journaldev.com/22504/python-eval-function

에서nested_parse()기능, 나는 확실히 하지 않았다.__builtins__글로벌을 사용할 수 있으며 사용할 수 있는 로컬 변수만nest사전.

언급URL : https://stackoverflow.com/questions/14692690/access-nested-dictionary-items-via-a-list-of-keys

반응형