簡體   English   中英

Python:在深度嵌套的字典中更新值

[英]Python: Updating a value in a deeply nested dictionary

我正在導入和處理一些深度嵌套的JSON(作為字典導入)。 它可以使用以下代碼來分配值:

query['query']['function_score']['query']['multi_match']['operator'] = 'or'
query['query']['function_score']['query']['multi_match'].update({
        'minimum_should_match' : '80%' })  

但這很丑陋而且笨拙。 我想知道是否有一種更干凈的方法將值分配給合理有效的深度嵌套鍵?

我已經讀過關於可能使用內存中的SQLlite數據庫的信息,但是經過一些操作之后,數據又回到了json中。

multi_match = query['query']['function_score']['query']['multi_match']
multi_match['operator'] = 'or'
multi_match.update({'minimum_should_match' : '80%' })

JSONPath(通過'jsonpath_rw')使它不再那么麻煩:

以前:

>>> query
{u'query': {u'function_score': {u'query': {u'multi_match': {u'min_should_match': u'20%'}}}}}

更新:

>>> found = jsonpath_rw.parse("$..multi_match").find(query)[0]
>>> found.value["operator"] == "or"
>>> found.value["min_should_match"] = "80%"`

然后:

>>> query
{u'query': {u'function_score': {u'query': {u'multi_match': {'min_should_match': '80%', u'operator': u'or'}}}}}

選擇的答案肯定是要走的路。 我(后來)發現的問題是我的嵌套鍵可以出現在不同的級別。 因此,我需要能夠遍歷字典並首先找到節點的路徑,然后進行更新或添加。

jsonpath_rw是立即解決方案,但是嘗試使用它時出現了一些奇怪的結果。 經過幾個小時的努力,我放棄了。

冒着被笨拙的newb擊倒的風險,我確實充實了一些功能(基於我在SO上找到的其他代碼),這些功能本機地可以滿足我的需求:

def find_in_obj(obj, condition, path=None):
    ''' generator finds full path to nested dict key when key is at an unknown level 
        borrowed from http://stackoverflow.com/a/31625583/5456148'''
    if path is None:
        path = []

    # In case this is a list
    if isinstance(obj, list):
        for index, value in enumerate(obj):
            new_path = list(path)
            new_path.append(index)
            for result in find_in_obj(value, condition, path=new_path):
                yield result

    # In case this is a dictionary
    if isinstance(obj, dict):
        for key, value in obj.items():
            new_path = list(path)
            new_path.append(key)
            for result in find_in_obj(value, condition, path=new_path):
                yield result

            if condition == key:
                new_path = list(path)
                new_path.append(key)
                yield new_path


def set_nested_value(nested_dict, path_list, key, value):
    ''' add or update a value in a nested dict using passed list as path
        borrowed from http://stackoverflow.com/a/11918901/5456148'''
    cur = nested_dict
    path_list.append(key)
    for path_item in path_list[:-1]:
        try:
            cur = cur[path_item]
        except KeyError:
            cur = cur[path_item] = {}

    cur[path_list[-1]] = value
    return nested_dict


def update_nested_dict(nested_dict, findkey, updatekey, updateval):
    ''' finds and updates values in nested dicts with find_in_dict(), set_nested_value()'''
    return set_nested_value(
        nested_dict,
        list(find_in_obj(nested_dict, findkey))[0],
        updatekey,
        updateval
    )

find_in_obj()是一個生成器,用於查找到給定嵌套鍵的路徑。

set_nested_values()將使用給定列表更新 dict中的鍵/值,或者如果不存在則添加它。

update_nested_dict()是兩個函數的“包裝器”,它們使用嵌套dict搜索,要查找的鍵和要更新的鍵值(如果不存在,則添加)。

所以我可以傳遞:

q = update_nested_dict(q, 'multi_match', 'operator', 'or')
q = update_nested_dict(q, 'multi_match', 'minimum_should_match', '80%')

並更新“運算符”值,並在“ multi_match”節點下添加“ minimum_should_match”鍵/值,無論其在字典中出現的級別如何。

如果搜索到的關鍵字存在於字典中的多個位置,則可能會遇到問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM