2011-01-13 20 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']} 

Esto obviamente no es simple intercambio de claves con valores: esto sobrescribiría algunos valores (como nuevas claves) que NO es lo que estoy buscando.smarter "reverse" de un diccionario en python (según algunos valores son los mismos)?

Si 2 o más valores son los mismos para claves diferentes, se supone que las claves se agrupan en una lista.

La función anterior funciona, pero me pregunto si hay una manera más inteligente/más rápida?

+0

Ha sido un tiempo desde que he usado Python, pero tal vez hay algo que podría hacer con 'setdefault()' en el dict , para colapsar las 4 líneas de la instrucción if en 1? – Ken

+1

¿podemos suponer que los valores del diccionario inicial son inmutables (calificar como claves), o podría ser una lista de tales? En otras palabras, ¿quieres que la función sea reversible? Supongo que no, ya que el tuyo no lo es, pero también podría ser un error en la implementación actual. – kriss

Respuesta

8

Eso se ve bastante bien. Se podría simplificarlo un poco mediante el uso de 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 Iba a publicar algo casi idéntico. Tenga en cuenta que esto no es necesariamente más rápido (como en, el tiempo sin procesar que se pasó haciéndolo) pero tiene la misma complejidad de tiempo y espacio y cualquier diferencia real será negativa. – delnan

+0

+1. Acabo de publicar una respuesta casi idéntica, luego la eliminé :) –

+0

no hay necesidad absoluta de importar defaultdict() – eyquem

0

Un enfoque alternativo. No estoy seguro si esto es más rápido (lo dudo).

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']} 

Su código inicial es, sin duda no está mal (legible) aunque probablemente lo hubiera escrito como éste (de preferencia en su mayoría personal, en realidad):

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

Probablemente no es tan eficiente, pero:

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 

me parece más legible para mí mismo. Alguna desventaja?

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

resultado

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

también:

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