lista - sort python code
Python 2.5 dictionary 2 key sort (6)
>>> keys = sorted(a, key=lambda k: (-a[k], k))
o
>>> keys = sorted(a)
>>> keys.sort(key=a.get, reverse=True)
entonces
print [(key, a[key]) for key in keys]
[(''keyB'', 2), (''keyA'', 1), (''keyC'', 1)]
Tengo un diccionario de 200,000 elementos (las teclas son cadenas y los valores son enteros).
¿Cuál es la forma mejor / más pitónica de imprimir los elementos ordenados por valor descendente y luego por orden 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)]
Aprovechando 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
La forma más pitónica de hacerlo sería conocer un poco más acerca de los datos reales, específicamente, el valor máximo que puede tener, 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 conozcas el valor máximo, buscar el valor máximo significa recorrer el dict un tiempo extra (con max(thedict.itervalues())
), que puede ser costoso. Alternativamente, una versión de Keyfunc de la solución de 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 el que desee mezclar la clasificación ascendente y descendente con la misma clave. Si valoras la brevedad, puedes escribir sortcmp como:
def sortcmp((ak, av), (bk, bv)):
return cmp((bk, av), (ak, bv))
No puedes ordenar diccionarios. Tienes que ordenar la lista de artículos.
Las versiones anteriores estaban equivocadas. 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, usando una función explícita en lugar de una lambda y la opción cmp en lugar de la clave.
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 géneros separados
b.sort( key=lambda a:a[1], reverse=True )
b.sort( key=lambda a:a[0] )
print b
Puedes 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é cuán pitónico es sin embargo :)
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