Question

Étant donné un dictionnaire comme celui-ci :

my_map = { 'a': 1, 'b':2 }

Comment inverser cette carte pour obtenir :

inv_map = { 1: 'a', 2: 'b' }
Était-ce utile?

La solution

Pour Python 2.7.x

inv_map = {v: k for k, v in my_map.iteritems()}

Pour Python 3 +:

inv_map = {v: k for k, v in my_map.items()}

Autres conseils

En supposant que les valeurs du dict sont uniques:

dict((v, k) for k, v in my_map.iteritems())

Si les valeurs entre my_map ne sont pas uniques:

inv_map = {}
for k, v in my_map.iteritems():
    inv_map[v] = inv_map.get(v, [])
    inv_map[v].append(k)

Pour ce faire tout en préservant le type de votre mappage (en supposant qu'il s'agisse d'une sous-classe dict ou <=>):

def inverse_mapping(f):
    return f.__class__(map(reversed, f.items()))

Essayez ceci:

inv_map = dict(zip(my_map.values(), my_map.keys()))

(Notez que les documents Python sur les vues de dictionnaire explicitement garantir que .keys() et .values() ont leurs éléments dans le même ordre, ce qui permet à l'approche ci-dessus de fonctionner.)

Alternativement:

inv_map = dict((my_map[k], k) for k in my_map)

ou en utilisant les interprétations dict de python 3.0

inv_map = {my_map[k] : k for k in my_map}

Une autre manière plus fonctionnelle:

my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))

Ceci développe la réponse https://stackoverflow.com/questions/ 483666 / python-reverse-inverse-a-mapping / 485368 # 485368 , à appliquer lorsque les valeurs du dict ne sont pas uniques.

class ReversibleDict(dict):

    def reversed(self):
        """
        Return a reversed dict, with common values in the original dict
        grouped into a list in the returned dict.

        Example:
        >>> d = ReversibleDict({'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2})
        >>> d.reversed()
        {1: ['d'], 2: ['c', 'b', 'f'], 3: ['a', 'e']}
        """

        revdict = {}
        for k, v in self.iteritems():
            revdict.setdefault(v, []).append(k)
        return revdict

L'implémentation est limitée en ce sens que vous ne pouvez pas utiliser reversed deux fois et récupérer l'original. Ce n'est pas symétrique en tant que tel. Il est testé avec Python 2.6. Voici un cas d'utilisation de la façon dont j'utilise pour imprimer le texte résultant.

Si vous préférez utiliser un set plutôt qu'un list, et qu'il existe des applications pour lesquelles cela a du sens, au lieu de setdefault(v, []).append(k), utilisez setdefault(v, set()).add(k).

Nous pouvons également inverser un dictionnaire avec des clés en double en utilisant defaultdict:

from collections import Counter, defaultdict

def invert_dict(d):
    d_inv = defaultdict(list)
    for k, v in c.items():
        d_inv[v].append(k)
    return d_inv

text = 'aaa bbb ccc ddd aaa bbb ccc aaa' 
c = Counter(text.split()) # Counter({'aaa': 3, 'bbb': 2, 'ccc': 2, 'ddd': 1})
dict(invert_dict(c)) # {1: ['ddd'], 2: ['bbb', 'ccc'], 3: ['aaa']}  

Voir ici :

  

Cette technique est plus simple et plus rapide qu'une technique équivalente utilisant dict.setdefault().

Combinaison de la liste et de la compréhension du dictionnaire. Peut gérer les clés en double

{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}

Ajout de mes 2 centimes de manière pythonique:

inv_map = dict(map(reversed, my_map.items()))

Exemple:

In [7]: my_map
Out[7]: {1: 'one', 2: 'two', 3: 'three'}

In [8]: inv_map = dict(map(reversed, my_map.items()))

In [9]: inv_map
Out[9]: {'one': 1, 'three': 3, 'two': 2}

Si les valeurs ne sont pas uniques et que vous êtes un peu hardcore:

inv_map = dict(
    (v, [k for (k, xx) in filter(lambda (key, value): value == v, my_map.items())]) 
    for v in set(my_map.values())
)

Notez que cette solution est beaucoup moins efficace que la réponse, surtout pour un dictée volumineuse Python inverse / inverse un mappage car il effectue une boucle sur items() plusieurs fois.

En plus des autres fonctions suggérées ci-dessus, si vous aimez lambdas:

invert = lambda mydict: {v:k for k, v in mydict.items()}

Ou vous pouvez le faire aussi:

invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )

Je pense que la meilleure façon de faire est de définir une classe. Voici une implémentation d'un & Quot; dictionnaire symétrique & Quot;:

class SymDict:
    def __init__(self):
        self.aToB = {}
        self.bToA = {}

    def assocAB(self, a, b):
        # Stores and returns a tuple (a,b) of overwritten bindings
        currB = None
        if a in self.aToB: currB = self.bToA[a]
        currA = None
        if b in self.bToA: currA = self.aToB[b]

        self.aToB[a] = b
        self.bToA[b] = a
        return (currA, currB)

    def lookupA(self, a):
        if a in self.aToB:
            return self.aToB[a]
        return None

    def lookupB(self, b):
        if b in self.bToA:
            return self.bToA[b]
        return None

Les méthodes de suppression et d'itération sont faciles à implémenter si elles sont nécessaires.

Cette implémentation est bien plus efficace que l’inversion d’un dictionnaire entier (ce qui semble être la solution la plus populaire sur cette page). Sans oublier de mentionner que vous pouvez ajouter ou supprimer des valeurs de votre SymDict autant que vous le souhaitez et que votre dictionnaire inverse restera toujours valide. Ce n'est pas le cas si vous inversez simplement le dictionnaire en entier une fois.

Utilisation de zip

inv_map = dict(zip(my_map.values(), my_map.keys()))

Cela gère les valeurs non uniques et conserve une grande partie de l’apparence du cas unique.

inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}

Pour Python 3.x, remplacez itervalues avec valeurs.Je ne peux pas m'en attribuer le mérite...cela a été suggéré par Icon Jack.

Essayez ceci pour Python 2.7 / 3.x

inv_map={};
for i in my_map:
    inv_map[my_map[i]]=i    
print inv_map

Par exemple, vous avez le dictionnaire suivant:

dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}

Et vous voulez l'obtenir sous une forme aussi inversée:

inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}

Première solution . Pour inverser les paires clé-valeur dans votre dictionnaire, utilisez l'approche for - en boucle:

# Use this code to invert dictionaries that have non-unique values

inverted_dict = dictio()
for key, value in dict.items():
    inverted_dict.setdefault(value, list()).append(key)

Deuxième solution . Utilisez une approche compréhension de dictionnaire pour l'inversion:

# Use this code to invert dictionaries that have unique values

inverted_dict = {value: key for key, value in dict.items()}

Troisième solution . Utilisez l'inversion :

# Use this code to invert dictionaries that have lists of values

dict = {value: key for key in inverted_dict for value in my_map[key]}

La fonction est symétrique pour les valeurs de type list; Les tuples sont convertis en listes lors de l'exécution de dict inverse (dict inversé)

def reverse_dict(dictionary):
    reverse_dict = {}
    for key, value in dictionary.iteritems():
        if not isinstance(value, (list, tuple)):
            value = [value]
        for val in value:
            reverse_dict[val] = reverse_dict.get(val, [])
            reverse_dict[val].append(key)
    for key, value in reverse_dict.iteritems():
        if len(value) == 1:
            reverse_dict[key] = value[0]
    return reverse_dict

Etant donné que les dictionnaires nécessitent une clé unique dans le dictionnaire, à la différence des valeurs, nous devons ajouter les valeurs inversées à une liste de tri afin de les inclure dans les nouvelles clés spécifiques.

def r_maping(dictionary):
    List_z=[]
    Map= {}
    for z, x in dictionary.iteritems(): #iterate through the keys and values
        Map.setdefault(x,List_z).append(z) #Setdefault is the same as dict[key]=default."The method returns the key value available in the dictionary and if given key is not available then it will return provided default value. Afterward, we will append into the default list our new values for the specific key.
    return Map

Je le ferais de cette façon en python 2.

inv_map = {my_map[x] : x for x in my_map}
def invertDictionary(d):
    myDict = {}
  for i in d:
     value = d.get(i)
     myDict.setdefault(value,[]).append(i)   
 return myDict
 print invertDictionary({'a':1, 'b':2, 'c':3 , 'd' : 1})

Ceci fournira une sortie sous la forme: {1: ['a', 'd'], 2: ['b'], 3: ['c']}

  def reverse_dictionary(input_dict):
      out = {}
      for v in input_dict.values():  
          for value in v:
              if value not in out:
                  out[value.lower()] = []

      for i in input_dict:
          for j in out:
              if j in map (lambda x : x.lower(),input_dict[i]):
                  out[j].append(i.lower())
                  out[j].sort()
      return out

ce code fait comme ceci:

r = reverse_dictionary({'Accurate': ['exact', 'precise'], 'exact': ['precise'], 'astute': ['Smart', 'clever'], 'smart': ['clever', 'bright', 'talented']})

print(r)

{'precise': ['accurate', 'exact'], 'clever': ['astute', 'smart'], 'talented': ['smart'], 'bright': ['smart'], 'exact': ['accurate'], 'smart': ['astute']}

Solution fonctionnelle rapide pour les cartes non bijectives (valeurs non uniques):

from itertools import imap, groupby

def fst(s):
    return s[0]

def snd(s):
    return s[1]

def inverseDict(d):
    """
    input d: a -> b
    output : b -> set(a)
    """
    return {
        v : set(imap(fst, kv_iter))
        for (v, kv_iter) in groupby(
            sorted(d.iteritems(),
                   key=snd),
            key=snd
        )
    }

En théorie, cela devrait être plus rapide que d’ajouter à l’ensemble (ou d’ajouter à la liste) un par un comme dans la solution impérative .

Malheureusement, les valeurs doivent être triables, le tri est requis par groupby.

Pas quelque chose de complètement différent, juste une recette un peu réécrite à partir de Cookbook. Il est en outre optimisé en conservant la setdefault méthode, au lieu de la faire passer à chaque fois par l'instance:

def inverse(mapping):
    '''
    A function to inverse mapping, collecting keys with simillar values
    in list. Careful to retain original type and to be fast.
    >> d = dict(a=1, b=2, c=1, d=3, e=2, f=1, g=5, h=2)
    >> inverse(d)
    {1: ['f', 'c', 'a'], 2: ['h', 'b', 'e'], 3: ['d'], 5: ['g']}
    '''
    res = {}
    setdef = res.setdefault
    for key, value in mapping.items():
        setdef(value, []).append(key)
    return res if mapping.__class__==dict else mapping.__class__(res)

Conçu pour être exécuté sous CPython 3.x, pour 2.x, remplacez mapping.items() par mapping.iteritems()

Sur ma machine, la vitesse d'exécution est légèrement supérieure à celle des autres exemples

.

Si les valeurs ne sont pas uniques ET peut être un hachage (une dimension):

for k, v in myDict.items():
    if len(v) > 1:
        for item in v:
            invDict[item] = invDict.get(item, [])
            invDict[item].append(k)
    else:
        invDict[v] = invDict.get(v, [])
        invDict[v].append(k)

Et avec une récursion si vous devez creuser plus profondément, alors une seule dimension:

def digList(lst):
    temp = []
    for item in lst:
        if type(item) is list:
            temp.append(digList(item))
        else:
            temp.append(item)
    return set(temp)

for k, v in myDict.items():
    if type(v) is list:
        items = digList(v)
        for item in items:
            invDict[item] = invDict.get(item, [])
            invDict[item].append(k)
    else:
        invDict[v] = invDict.get(v, [])
        invDict[v].append(k)

Inverse votre dictionnaire:

dict_ = {"k0":"v0", "k1":"v1", "k2":"v1"}
inversed_dict_ = {val: key for key, val in dict_.items()}

print(inversed_dict_["v1"])

J'ai écrit cela à l'aide du cycle 'pour' et de la méthode '.get ()' et j'ai changé le nom 'map' du dictionnaire en 'map1' car 'map' est une fonction.

def dict_invert(map1):
    inv_map = {} # new dictionary
    for key in map1.keys():
        inv_map[map1.get(key)] = key
    return inv_map

Pour tous les types de dictionnaires, vous pouvez créer une liste de clés pour chaque valeur, qu'ils ne possèdent pas de valeurs uniques à utiliser comme clés.

inv_map = {v: inv_map.get(v, []) + [k] for k,v in my_map.items()}

Ce n’est pas la meilleure solution, mais cela fonctionne. Disons que le dictionnaire que nous voulons inverser est le suivant:

dictionary = {'a': 1, 'b': 2, 'c': 3}, puis:

dictionary = {'a': 1, 'b': 2, 'c': 3}
reverse_dictionary = {}
for index, val in enumerate(list(dictionary.values())):
    reverse_dictionary[val] = list(dictionary.keys())[index]

Le résultat de reverse_dictionary devrait être {1: 'a', 2: 'b', 3: 'c'}

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top