2008-10-01 10 views
14

Tengo un diccionario de 200,000 elementos (las claves son cadenas y los valores son enteros).Python 2.5 diccionario 2 tipo de clave

¿Cuál es la forma mejor/más pythonic de imprimir los elementos ordenados por valor descendente y luego por la tecla ascendente (es decir, un orden de 2 teclas)?

a={ 'keyC':1, 'keyB':2, 'keyA':1 } 
b = a.items() 
b.sort(key=lambda a:a[0]) 
b.sort(key=lambda a:a[1], reverse=True) 
print b 
>>>[('keyB', 2), ('keyA', 1), ('keyC', 1)] 
+0

Véase mi respuesta a una pregunta relacionada [aquí] (http://stackoverflow.com/questions/1143671/python-sorting-list-of- dictionaries-by-multiple-keys/1144405). – hughdbrown

Respuesta

17

No se pueden ordenar los diccionarios. Tienes que ordenar la lista de artículos.

Las versiones anteriores eran incorrectas. Cuando tiene un valor numérico, es fácil ordenarlo en orden inverso. Esto hará eso. Pero esto no es general. Esto solo funciona porque el valor es numérico.

a = { 'key':1, 'another':2, 'key2':1 } 

b= a.items() 
b.sort(key=lambda a:(-a[1],a[0])) 
print b 

Aquí hay una alternativa, utilizando una función explícita en lugar de una lambda y la opción cmp en lugar de la tecla.

def valueKeyCmp(a, b): 
    return cmp((-a[1], a[0]), (-b[1], b[0])) 

b.sort(cmp= valueKeyCmp) 
print b 

La solución más general es en realidad dos tipos separados

b.sort(key=lambda a:a[1], reverse=True) 
b.sort(key=lambda a:a[0]) 
print b 
+0

Gracias, pero esto no aborda el orden de clasificación o la naturaleza de dos claves del género. –

+0

Sí. Me di cuenta de eso. Lo siento. Repostado con correcciones. –

+0

El tercer ejemplo no hace una clasificación de 2 teclas, la segunda clasificación deshace la primera –

1

La forma más Pythonic hacerlo sería saber un poco más sobre los datos reales - en concreto, el valor máximo que puede tienen - y luego hacerlo de esta manera:

def sortkey((k, v)): 
    return (maxval - v, k) 

items = thedict.items() 
items.sort(key=sortkey) 

pero a menos que ya conoce el valor máximo, buscando el valor máximo significa bucle a través de la dict un tiempo extra (con max(thedict.itervalues())), que puede ser costoso. De forma alternativa, una versión de la solución de keyfunc S. Lott:

def sortkey((k, v)): 
    return (-v, k) 

items = thedict.items() 
items.sort(key=sortkey) 

Una alternativa que no se preocupa por los tipos sería una función de comparación:

def sortcmp((ak, av), (bk, bv)): 
    # compare values 'in reverse' 
    r = cmp(bv, av) 
    if not r: 
     # and then keys normally 
     r = cmp(ak, bk) 
    return r 

items = thedict.items() 
items.sort(cmp=sortcmp) 

y esta solución realmente funciona para cualquier tipo de clave y valor con los que desea mezclar la ordenación ascendente y descendente con la misma clave. Si el valor de la brevedad se puede escribir como sortcmp:

def sortcmp((ak, av), (bk, bv)): 
    return cmp((bk, av), (ak, bv)) 
+0

Conocer el valor máximo es inútil; usa cualquier valor como valor máximo. Me viene a la mente al instante, como sugirió S.Lott. ;) – tzot

0

Puede usar algo como esto:

dic = {'aaa':1, 'aab':3, 'aaf':3, 'aac':2, 'aad':2, 'aae':4} 

def sort_compare(a, b): 
    c = cmp(dic[b], dic[a]) 
    if c != 0: 
     return c 
    return cmp(a, b) 

for k in sorted(dic.keys(), cmp=sort_compare): 
    print k, dic[k] 

No sé cómo Pythonic es sin embargo :)

6
data = { 'keyC':1, 'keyB':2, 'keyA':1 } 

for key, value in sorted(data.items(), key=lambda x: (-1*x[1], x[0])): 
    print key, value 
+0

Esta es la solución más pitonica en mi opinión y la más fácil de entender. –

+2

Esto ordena por valor, no clave. –

0

construcción sobre las soluciones de Thomas Wouters y Ricardo Reyes:

def combine(*cmps): 
    """Sequence comparisons.""" 
    def comparator(a, b): 
     for cmp in cmps: 
      result = cmp(a, b): 
      if result: 
       return result 
     return 0 
    return comparator 

def reverse(cmp): 
    """Invert a comparison.""" 
    def comparator(a, b): 
     return cmp(b, a) 
    return comparator 

def compare_nth(cmp, n): 
    """Compare the n'th item from two sequences.""" 
    def comparator(a, b): 
     return cmp(a[n], b[n]) 
    return comparator 

rev_val_key_cmp = combine(
     # compare values, decreasing 
     reverse(compare_nth(1, cmp)), 

     # compare keys, increasing 
     compare_nth(0, cmp) 
    ) 

data = { 'keyC':1, 'keyB':2, 'keyA':1 } 

for key, value in sorted(data.items(), cmp=rev_val_key_cmp): 
    print key, value 
0
>>> keys = sorted(a, key=lambda k: (-a[k], k)) 

o

>>> keys = sorted(a) 
>>> keys.sort(key=a.get, reverse=True) 

continuación

print [(key, a[key]) for key in keys] 
[('keyB', 2), ('keyA', 1), ('keyC', 1)] 
Cuestiones relacionadas