34

ネストされた辞書のキーのドットを置き換える汎用関数を作成しようとしています。3 レベルの深さの非ジェネリック関数がありますが、このジェネリックを実行する方法が必要です。どんな助けでも大歓迎です!これまでの私のコード:

output = {'key1': {'key2': 'value2', 'key3': {'key4 with a .': 'value4', 'key5 with a .': 'value5'}}} 

def print_dict(d):
    new = {}
    for key,value in d.items():
        new[key.replace(".", "-")] = {}
        if isinstance(value, dict):
            for key2, value2 in value.items():
                new[key][key2] = {}
                if isinstance(value2, dict):
                    for key3, value3 in value2.items():
                        new[key][key2][key3.replace(".", "-")] = value3
                else:
                    new[key][key2.replace(".", "-")] = value2
        else:
            new[key] = value
    return new

print print_dict(output)

更新: 私自身の質問に答えるために、json object_hooks を使用してソリューションを作成しました:

import json

def remove_dots(obj):
    for key in obj.keys():
        new_key = key.replace(".","-")
        if new_key != key:
            obj[new_key] = obj[key]
            del obj[key]
    return obj

output = {'key1': {'key2': 'value2', 'key3': {'key4 with a .': 'value4', 'key5 with a .': 'value5'}}}
new_json = json.loads(json.dumps(output), object_hook=remove_dots) 

print new_json
4

9 に答える 9

44

はい、より良い方法があります:

def print_dict(d):
    new = {}
    for k, v in d.iteritems():
        if isinstance(v, dict):
            v = print_dict(v)
        new[k.replace('.', '-')] = v
    return new

(編集: 再帰です。ウィキペディアの詳細を参照してください。)

于 2012-07-28T11:58:01.453 に答える
20

実際、すべての回答には間違いが含まれており、結果の入力ミスにつながる可能性があります。

@ngenain の回答を参考にして、以下で少し改善します。

dict私のソリューションは、 ( OrderedDictdefaultdict、など)から派生した型と、 だけlistでなくsetandtuple型にも注意を払います。

また、最も一般的な型の関数の最初で簡単な型チェックを行い、比較回数を減らします (大量のデータで速度が向上する可能性があります)。

Python 3obj.items()で動作しますobj.iteritems()。Py2 用に置き換えます。

def change_keys(obj, convert):
    """
    Recursively goes through the dictionary obj and replaces keys with the convert function.
    """
    if isinstance(obj, (str, int, float)):
        return obj
    if isinstance(obj, dict):
        new = obj.__class__()
        for k, v in obj.items():
            new[convert(k)] = change_keys(v, convert)
    elif isinstance(obj, (list, set, tuple)):
        new = obj.__class__(change_keys(v, convert) for v in obj)
    else:
        return obj
    return new

ニーズを正しく理解していれば、ほとんどのユーザーは、キー名にドットを使用できない mongoDB でキーを使用するようにキーを変換したいと考えています。

于 2016-07-08T15:06:52.243 に答える
7

ネストされたリストと辞書を扱う単純な再帰的なソリューションを次に示します。

def change_keys(obj, convert):
    """
    Recursivly goes through the dictionnary obj and replaces keys with the convert function.
    """
    if isinstance(obj, dict):
        new = {}
        for k, v in obj.iteritems():
            new[convert(k)] = change_keys(v, convert)
    elif isinstance(obj, list):
        new = []
        for v in obj:
            new.append(change_keys(v, convert))
    else:
        return obj
    return new
于 2016-02-10T10:55:34.357 に答える
7

@horejsek のコードを使用しましたが、リストと文字列を置き換える関数を使用して、ネストされた辞書を受け入れるように調整しました。

同様の問題を解決する必要がありました。アンダースコア小文字規則のキーをキャメルケース規則に置き換えたい、またはその逆にしたかったのです。

def change_dict_naming_convention(d, convert_function):
    """
    Convert a nested dictionary from one convention to another.
    Args:
        d (dict): dictionary (nested or not) to be converted.
        convert_function (func): function that takes the string in one convention and returns it in the other one.
    Returns:
        Dictionary with the new keys.
    """
    new = {}
    for k, v in d.iteritems():
        new_v = v
        if isinstance(v, dict):
            new_v = change_dict_naming_convention(v, convert_function)
        elif isinstance(v, list):
            new_v = list()
            for x in v:
                new_v.append(change_dict_naming_convention(x, convert_function))
        new[convert_function(k)] = new_v
    return new
于 2015-11-12T09:43:46.450 に答える