Python reverse / invert a mapping

Mając taki słownik:

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

Jak można odwrócić tę mapę, aby uzyskać:

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

Uwaga redaktora: map zmieniono na my_map, aby uniknąć konfliktów z wbudowaną funkcją map. Niektóre komentarze mogą ulec zmianie poniżej.

Author: Brian M. Hunt, 2009-01-27

29 answers

Dla Pythona 2.7.x

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

Dla Pythona 3+:

inv_map = {v: k for k, v in my_map.items()}
 638
Author: SilentGhost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-14 16:21:01

Zakładając, że wartości w dict są unikalne:

dict((v, k) for k, v in my_map.iteritems())
 160
Author: Rick Teachey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-21 12:51:50

Jeśli wartości w my_map nie są unikalne:

inv_map = {}
for k, v in my_map.iteritems():
    inv_map[v] = inv_map.get(v, [])
    inv_map[v].append(k)
 107
Author: Robert Rossney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-21 12:52:19
def inverse_mapping(f):
    return f.__class__(map(reversed, f.items()))
 33
Author: fs.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-05 10:41:30

Spróbuj tego:

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

(zauważ, że dokumenty Pythona dotyczące widoków słownika wyraźnie gwarantują, że .keys() i .values() mają swoje elementy w tej samej kolejności, co pozwala na działanie powyższego podejścia.)

Alternatywnie:

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

Lub używając składni dict Pythona 3.0

inv_map = {my_map[k] : k for k in my_map}
 29
Author: sykora,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-21 12:51:33

Inny, bardziej funkcjonalny sposób:

my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
 17
Author: Brendan Maguire,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-05 14:51:23

To rozszerza ODPOWIEDŹ Python odwraca / odwraca mapowanie , stosując się do sytuacji, gdy wartości w dict nie są unikalne.

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

Implementacja jest ograniczona tym, że nie można użyć reversed dwa razy i odzyskać oryginału. Nie jest ona symetryczna jako taka. Jest testowany z Pythonem 2.6. tutaj {[8] } jest przykład użycia, jak używam do drukowania wynikowego dict.

Jeśli wolisz używać set niż list, A są aplikacje, dla których ma to sens, zamiast z setdefault(v, []).append(k), Użyj setdefault(v, set()).add(k).

 6
Author: A-B-B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:41

Dodaję moje 2 grosze pythonicznej drogi:

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

Przykład:

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
Author: Amit Kushwaha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-03 05:39:53

Jeśli wartości nie są unikalne, a Ty jesteś trochę 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())
)

Szczególnie dla dużego dict, zauważ, że to rozwiązanie jest znacznie mniej efektywne niż odpowiedź Python odwraca / odwraca mapowanie , ponieważ pętli over items() wiele razy.

 4
Author: pcv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:43

Możemy również odwrócić słownik za pomocą zduplikowanych klawiszy używając 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']}  

Zobacz tutaj :

Ta technika jest prostsza i szybsza niż równoważna technika z użyciem dict.setdefault().

 4
Author: irudyak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-26 23:14:08

Połączenie listy i rozumienia słownika. Może obsługiwać zduplikowane klucze

{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
 4
Author: SVJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-19 03:28:14

Oprócz innych funkcji sugerowanych powyżej, jeśli lubisz lambdy:

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

Lub, można to zrobić również w ten sposób:

invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )
 3
Author: RussellStewart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-08 21:28:48

To obsługuje nie-unikalne wartości i zachowuje większość wyglądu unikalnej obudowy.

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

Dla Pythona 3.x, zamień itervalues na wartości . Nie mogę sobie tego przypisać... zasugerował: Icon Jack

 3
Author: user1495,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-25 20:29:24

Myślę, że najlepszym sposobem na to jest zdefiniowanie klasy. Oto implementacja "słownika symetrycznego":

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

Metody usuwania i iteracji są wystarczająco łatwe do wdrożenia, jeśli są potrzebne.

Ta implementacja jest o wiele wydajniejsza niż odwrócenie całego słownika (co wydaje się być najpopularniejszym rozwiązaniem na tej stronie). Nie wspominając o tym, że możesz dodawać lub usuwać wartości z SymDict tak bardzo, jak chcesz, a Twój Słownik odwrotny zawsze pozostanie ważny -- to nie jest PRAWDA, jeśli po prostu odwrócić cały słownik raz.

 2
Author: NcAdams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-28 07:18:45

Using zip

inv_map = dict(zip(my_map.values(), my_map.keys()))
 2
Author: Kwaw Annor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-11 22:26:46

Spróbuj tego dla Pythona 2.7/3.x

inv_map={};
for i in my_map:
    inv_map[my_map[i]]=i    
print inv_map
 1
Author: dhvlnyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-21 12:56:08

Zrobiłbym to tak w Pythonie 2.

inv_map = {my_map[x] : x for x in my_map}
 1
Author: genghiscrade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
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})

To wyświetli wyjście jako: {1: ['a', 'd'], 2: ['b'], 3: ['c']}

 1
Author: RVR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
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

Ten kod robi tak:

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
Author: Shb8086,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-14 16:06:43

Funkcja jest symetryczna dla wartości typu list; krotki są zakrywane do list podczas wykonywania 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
Author: Alf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-24 12:29:56

Ponieważ słowniki wymagają jednego unikalnego klucza w słowniku, w przeciwieństwie do wartości, musimy dołączyć odwrócone wartości do Listy sortowania, która ma być uwzględniona w nowych określonych kluczach.

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
Author: EyoelD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-09 01:38:16

Nie coś zupełnie innego, tylko trochę przepis przepisany z książki kucharskiej. Jest on dodatkowo optymalizowany przez metodę retaining setdefault, zamiast za każdym razem uzyskiwania go przez instancję:

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)

Zaprojektowany do pracy pod CPython 3.x, za 2.x zastąp mapping.items() przez mapping.iteritems()

Na mojej maszynie działa nieco szybciej, niż inne przykłady tutaj

 0
Author: thodnev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-02 18:08:53

Jeśli wartości nie są unikalne i mogą być hash (jeden wymiar):

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)

I z rekurencją jeśli trzeba kopać głębiej to tylko jeden wymiar:

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
Author: mveith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-10 11:06:59

Odwróć swój słownik:

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

print(inversed_dict_["v1"])
 0
Author: Miladiouss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-07 23:37:46

Szybkie rozwiązanie funkcjonalne dla Map nie bijektywnych (wartości nie unikalne):

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

Teoretycznie powinno to być szybsze niż dodawanie do zbioru (lub dodawanie do listy) jeden po drugim, jak wimperatywnym rozwiązaniu .

Niestety wartości muszą być sortowalne, sortowanie jest wymagane przez groupby.

 -1
Author: cjay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:30

Napisałem to za pomocą cyklu " dla "i metody".get () 'i zmieniłem nazwę' map 'słownika na' map1 'ponieważ' map ' jest funkcją.

def dict_invert(map1):
    inv_map = {} # new dictionary
    for key in map1.keys():
        inv_map[map1.get(key)] = key
    return inv_map
 -1
Author: Taras Voitovych,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-05 21:14:02

Dla wszystkich rodzajów słownika, bez względu na to, czy nie mają unikalnych wartości do użycia jako klucze, możesz utworzyć listę kluczy dla każdej wartości

inv_map = {v: inv_map.get(v, []) + [k] for k,v in my_map.items()}
 -3
Author: beco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-21 12:53:58

To nie jest najlepsze rozwiązanie, ale działa. Załóżmy, że słownik, który chcemy odwrócić, to:

Słownik = {"A": 1, "b": 2, "c": 3}, Następnie:

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

Wyjście reverse_dictionary powinno być {1: "a", 2: "b", 3: "c"}

 -3
Author: user9918114,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-16 12:23:23

Jeśli elementy nie są unikalne spróbuj tego:

     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
Author: seiferas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-24 18:17:03