1
votes

Obtenir toutes les clés parents dans le dictionnaire imbriqué pour tous les éléments

Je souhaite obtenir toutes les clés parentes pour tous les éléments d'un dictionnaire python imbriqué avec des niveaux illimités. Prenez une analogie, si vous pensez à un dictionnaire imbriqué comme un répertoire contenant des sous-répertoires, le comportement que je souhaite est similaire à ce que fait glob.glob (dir, recursive = True) .

Pour exemple, supposons que nous ayons le dictionnaire suivant:

["key_1", "sub_key_1", 1]
["key_1", "sub_key_2", 2]
["key_2", "sub_key_1", 3]
["key_2", "sub_key_2", "sub_sub_key_1", 4]

Je veux obtenir le "chemin" complet de chaque valeur du dictionnaire:

sample_dict = {
  "key_1": {
    "sub_key_1": 1,
    "sub_key_2": 2,
  },
  "key_2": {
    "sub_key_1": 3,
    "sub_key_2": {
      "sub_sub_key_1": 4,
    },
  },
}


5 commentaires

Qu'avez-vous essayé? Quel est le problème, exactement?


Le problème est que je ne sais pas comment faire cela. Je pense que la solution @Mark Meyer est la voie à suivre.


Pourquoi avez-vous besoin de faire cela? Cela semble un peu étrange et malheureux.


C'est une question abstraite dérivée d'un problème pratique dans mon travail. Cela peut donc sembler un peu étrange à cause de l'abstraction.


Quel est le problème pratique alors lol


3 Réponses :


2
votes

Vous pouvez le résoudre récursivement

sample_dict = {
  "key_1": {
    "sub_key_1": 1,
    "sub_key_2": 2,
  },
  "key_2": {
    "sub_key_1": 3,
    "sub_key_2": {
      "sub_sub_key_1": 4,
    },
  }
}

def full_paths(sample_dict, paths=[], parent_keys=[]):
    for key in sample_dict.keys():
        if type(sample_dict[key]) is dict:
            full_paths(sample_dict[key], paths=paths, parent_keys=(parent_keys + [key]))
        else:
            paths.append(parent_keys + [key] + [sample_dict[key]])
    return paths

print(full_paths(sample_dict))


1 commentaires

Merci de votre aide. Je pense qu'utiliser isinstance est mieux comme suggéré par Mark Meyer et Shivam Gupta.



3
votes

L'utilisation de générateurs peut souvent simplifier le code de ce type de tâches et les rendre beaucoup plus lisibles tout en évitant de passer des arguments d'état explicites à la fonction. Vous obtenez un générateur au lieu d'une liste, mais c'est une bonne chose car vous pouvez évaluer paresseusement si vous le souhaitez. Par exemple:

[['key_1', 'sub_key_1', 1],
 ['key_1', 'sub_key_2', 2],
 ['key_2', 'sub_key_1', 3],
 ['key_2', 'sub_key_2', 'sub_sub_key_1', 4]]

Le résultat sera:

def getpaths(d):
    if not isinstance(d, dict):
        yield [d]
    else:
        yield from ([k] + w for k, v in d.items() for w in getpaths(v))

result = list(getpaths(sample_dict))


1 commentaires

Merci! C'est vraiment une solution élégante!



2
votes

Vous pouvez utiliser cette solution.

sample_dict = {
  "key_1": {
    "sub_key_1": 1,
    "sub_key_2": 2,
  },
  "key_2": {
    "sub_key_1": 3,
    "sub_key_2": {
      "sub_sub_key_1": 4,
    },
  },
}

def key_find(sample_dict, li=[]):
    for key, val in sample_dict.items():
        if isinstance(val, dict):
            key_find(val, li=li + [key])
        else:
            print(li + [key] + [val])

key_find(sample_dict)


0 commentaires