Python inverse / inverser une cartographie

donné un dictionnaire comme ceci:

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

Comment peut-on inverser cette carte pour obtenir:

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

NOTE de l'ÉDITEUR: map changé en my_map pour éviter les conflits avec la fonction intégrée map . Certains commentaires peuvent être modifiés ci-dessous.

462
demandé sur Brian M. Hunt 2009-01-27 17:46:09

29 réponses

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()}
638
répondu SilentGhost 2016-10-14 16:21:01

en supposant que les valeurs dans le dict sont uniques:

dict((v, k) for k, v in my_map.iteritems())
160
répondu Rick Teachey 2016-08-21 12:51:50

si les valeurs de 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)
107
répondu Robert Rossney 2016-08-21 12:52:19
def inverse_mapping(f):
    return f.__class__(map(reversed, f.items()))
33
répondu fs. 2009-11-05 10:41:30

essayez ceci:

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

(notez que the Python docs on dictionary views garantit explicitement 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 compréhensions dict de python 3.0

inv_map = {my_map[k] : k for k in my_map}
29
répondu sykora 2016-08-21 12:51:33

une autre façon plus fonctionnelle:

my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
17
répondu Brendan Maguire 2017-01-05 14:51:23

ceci développe la réponse Python reverse / invert a mapping , s'appliquant lorsque les valeurs dans le 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 que vous ne pouvez pas utiliser reversed deux fois et récupérer l'original. Elle n'est pas symétrique en tant que telle. Il est testé avec la version 2.6 de Python. Ici est un cas d'utilisation de la façon dont j'utilise pour imprimer la résultante dict.

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

6
répondu A-B-B 2017-05-23 11:54:41

ajoutant mes 2 cents de pythonic way:

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}
5
répondu Amit Kushwaha 2017-04-03 05:39:53

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())
)

surtout pour un grand dict, notez que cette solution est beaucoup moins efficace que la réponse Python reverse / invert a mapping parce qu'elle boucle sur items() plusieurs fois.

4
répondu pcv 2017-05-23 12:34:43

nous pouvons également inverser un dictionnaire avec des clés dupliquées 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() .

4
répondu irudyak 2016-12-26 23:14:08

Combinaison de la liste et de la compréhension du dictionnaire. Peut manipuler des clés en double

{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
4
répondu SVJ 2018-04-19 03:28:14

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 bien, vous pourriez faire de cette façon:

invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )
3
répondu RussellStewart 2014-03-08 21:28:48

cela gère des 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, remplacer itervalues par values . Je ne peux pas prendre le crédit pour cela... il a été suggéré par Icon Jack.

3
répondu user1495 2017-01-25 20:29:24

je pense que la meilleure façon de le faire est de définir une classe. Voici une implémentation d'un "dictionnaire symétrique":

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 assez faciles à mettre en œuvre si elles sont nécessaires.

cette implémentation est beaucoup plus efficace que l'inversion d'un dictionnaire entier (qui semble être la solution la plus populaire sur cette page). Sans mentionner, vous pouvez ajouter ou supprimer des valeurs de votre SymDict autant que vous voulez, et votre dictionnaire inverse restera toujours valide -- ce n'est pas vrai si vous renversez simplement le dictionnaire entier une fois.

2
répondu NcAdams 2014-09-28 07:18:45

utilisant zip

inv_map = dict(zip(my_map.values(), my_map.keys()))
2
répondu Kwaw Annor 2016-09-11 22:26:46

essayez ceci pour python 2.7/3.x

inv_map={};
for i in my_map:
    inv_map[my_map[i]]=i    
print inv_map
1
répondu dhvlnyk 2016-08-21 12:56:08

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

inv_map = {my_map[x] : x for x in my_map}
1
répondu genghiscrade 2017-08-02 22:24:05
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})

Cela permettra de fournir de sortie : {1: ['a', 'd'], 2: ["b"], 3: ['c']}

1
répondu RVR 2017-08-30 10:11:43
  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']}
1
répondu Shb8086 2018-07-14 16:06:43

fonction est symétrique pour les valeurs de liste de type; Tuples sont couverts à des listes lors de l'exécution de reverse_dict (reverse_dict (dictionary))

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
0
répondu Alf 2014-09-24 12:29:56

puisque les dictionnaires nécessitent une clé unique dans le dictionnaire contrairement aux valeurs, nous devons ajouter les valeurs inversées dans une liste de tri pour être inclus 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
0
répondu EyoelD 2016-01-09 01:38:16

pas quelque chose de complètement différent, juste une recette un peu réécrite du Livre De Cuisine. De plus, il est optimisé en conservant la méthode setdefault , au lieu de 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 fonctionner sous CPython 3.x, pour 2.x remplacer mapping.items() par mapping.iteritems()

sur ma machine fonctionne un peu plus vite ,que d'autres exemples ici""

0
répondu thodnev 2016-08-02 18:08:53

si les valeurs ne sont pas uniques et peuvent ê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 avez besoin de creuser plus profond alors juste une 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)
0
répondu mveith 2017-01-10 11:06:59

Inverse ton dictionnaire:

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

print(inversed_dict_["v1"])
0
répondu Miladiouss 2018-06-07 23:37:46

Fast solution fonctionnelle pour les non-bijective des cartes (les valeurs ne sont pas 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 l'ajout à l'ensemble (ou l'ajout à la liste) un par un comme dans la solution impérative .

malheureusement les valeurs doivent être sortables, le tri est requis par groupby.

-1
répondu cjay 2017-05-23 12:10:30

j'ai écrit ceci avec l'aide du cycle 'pour' et de la méthode '.get () "et j'ai changé le nom de "carte" du dictionnaire de "map1" parce que '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
-1
répondu Taras Voitovych 2016-08-05 21:14:02

pour toutes sortes de dictionnaires, peu importe s'ils n'ont pas de valeurs uniques à utiliser comme clés, vous pouvez créer une liste de clés pour chaque valeur

inv_map = {v: inv_map.get(v, []) + [k] for k,v in my_map.items()}
-3
répondu beco 2016-08-21 12:53:58

Ce n'est pas la meilleure solution, mais il fonctionne. Disons que le dictionnaire que nous voulons Inverser est:

dictionnaire = {'a': 1, 'b': 2, 'c': 3}, alors:

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

La sortie de reverse_dictionary, devrait être {1: 'a', 2: 'b', 3: 'c'}

-3
répondu user9918114 2018-06-16 12:23:23

si les articles ne sont pas uniques essayez ceci:

     dict={}
     dict1={}
     num=int(raw_input(" how many numbers in dict?--> "))
     for i in range (0,num):
         key=raw_input(" enter key --> ")
         value=raw_input("enter value --> ")
         dict[key]=value
     keys=dict.keys()
     values=dict.values()
     for b in range (0,num):
         keys[b],values[b]=values[b],keys[b]
         dict1[keys[b]]=values[b]
     print keys
     print values
     print dict1
-5
répondu seiferas 2015-11-24 18:17:03