2011-01-13 9 views
5
def revert_dict(d): 
    rd = {} 
    for key in d: 
     val = d[key] 
     if val in rd: 
      rd[val].append(key) 
     else: 
      rd[val] = [key] 
    return rd 

>>> revert_dict({'srvc3': '1', 'srvc2': '1', 'srvc1': '2'}) 
{'1': ['srvc3', 'srvc2'], '2': ['srvc1']} 

Questo ovviamente non è semplice scambio di chiavi con valori: questo sovrascriverebbe alcuni valori (come nuove chiavi) che NON è quello che sto cercando."reverse" più intelligente di un dizionario in python (acc per alcuni dei valori uguali)?

Se 2 o più valori sono uguali per chiavi diverse, è necessario raggruppare i tasti in un elenco.

La funzione precedente funziona, ma mi chiedo se esiste un modo più intelligente/più veloce?

+0

E 'stato un po' che ho usato Python, ma forse c'è qualcosa che si potrebbe fare con 'setDefault()' sul dict , per comprimere le 4 righe dell'istruzione if in 1? – Ken

+1

possiamo supporre che i valori del dizionario iniziale siano immutabili (qualificati come chiavi), o potrebbe essere un elenco di tali? In altre parole, vuoi che la funzione sia inversibile? Immagino di no, come il tuo non lo è, ma potrebbe anche essere un bug all'attuale implementazione. – kriss

risposta

8

Sembra abbastanza buono. Si potrebbe semplificare un po 'utilizzando defaultdict:

import collections 

def revert_dict(d): 
    rd = collections.defaultdict(list) 

    for key, value in d.iteritems(): 
     rd[value].append(key) 

    return rd 
+0

+1 Stavo per pubblicare qualcosa di quasi identico. Si noti che questo non è necessariamente più veloce (come nel tempo grezzo impiegato a farlo) ma ha la stessa complessità di tempo e spazio e qualsiasi differenza effettiva sarà negata. – delnan

+0

+1. Ho appena postato una risposta quasi identica, quindi l'ho cancellata :) –

+0

non è assolutamente necessario importare defaultdict() – eyquem

0

Un approccio alternativo. Non sono sicuro se questo è più veloce (ne dubito).

from itertools import groupby 

old_dict = {'srvc3': '1', 'srvc2': '1', 'srvc1': '2'} 
funcval = d.__getitem__ 
new_dict = dict((val, list(keys)) for val, keys in \ 
       groupby(sorted(d.iterkeys(), key=funcval), funcval)) 

# new_dict: 
# {'1': ['srvc3', 'srvc2'], '2': ['srvc1']} 

tuo codice iniziale non è certo male (leggibile) anche se mi sarebbe probabilmente scritto in questo modo (preferenza per lo più personali, in realtà):

def revert_dict(d): 
    rd = {} 
    for key, val in d.items(): 
     try: 
      rd[val].append(key) 
     except KeyError: 
      rd[val] = [key] 
    return rd 
0

Probabilmente non come efficiente, ma:

ks, vs = old_dict.items() 
new_dict = dict((v, [k for k in ks if old_dict[k] == v]) for v in set(vs)) 
0
def invertDictionary(d): 
    rd = {} 
    for x,y in d.iteritems(): 
      if y in rd.keys(): 
        rd[y].append(x) 
      else: 
        rd[y] = [x] 
    return rd 

Trovo questo più leggibile a me stesso. Eventuali aspetti negativi?

0
def revert_dict(d): 
    rd = {} 
    for key,val in d.iteritems(): 
     rd[val] = rd.get(val,[]) + [key] 
    return rd 


print revert_dict({'srvc3': '1', 'srvc2': '1', 'srvc1': '2', 
      'srvc4': '8', 'srvc5': '2', 'srvc6': '2', 
      'srvc7': '77', 'srvc8': '1', 'srvc9': '2', 
      'srvc10': '3', 'srvc11': '1'}) 

risultato

{'1': ['srvc11', 'srvc3', 'srvc2', 'srvc8'], '77': ['srvc7'], '3': ['srvc10'], '2': ['srvc6', 'srvc5', 'srvc1', 'srvc9'], '8': ['srvc4']} 

anche:

def revert_dict(d): 
    rd = {} 
    for key,val in d.iteritems(): 
     rd[val] = rd[val]+ [key] if val in rd else [key] 
    return rd 
Problemi correlati