2010-11-05 21 views
15

Considere este formato de diccionario.Ordenar el diccionario anidado por valor y el resto por otro valor en Python

{'KEY1':{'name':'google','date':20100701,'downloads':0}, 
'KEY2':{'name':'chrome','date':20071010,'downloads':0}, 
'KEY3':{'name':'python','date':20100710,'downloads':100}} 

Me gustaría que el diccionario estuviera ordenado por descargas primero, y luego todos los elementos sin descargas ordenados por fecha. Obviamente, no se puede ordenar un diccionario, solo necesito una lista ordenada de claves que pueda repetir.

['KEY3','KEY1','KEY2'] 

ya puedo ordenar la lista por cualquiera de los valores utilizando sorted, pero ¿cómo puedo ordenar por segundo valor también?

Respuesta

25

utilizar el argumento de keysorted(). Le permite especificar una función que, dado el elemento real que se está ordenando, devuelve un valor que debe ordenarse por. Si este valor es una tupla, entonces ordena como las tuplas ordenan - por el primer valor, y luego por el segundo valor.

sorted(your_list, key=lambda x: (your_dict[x]['downloads'], your_dict[x]['date'])) 
+1

¡Línea muy bonita! Aquí se explica cómo puede invertir el orden de la clasificación: simplemente agregue 'reverse = True' como un parámetro a la función' sorted', al final. Gracias – otmezger

+0

Cambie a la de arriba.your_list = sorted (your_dict, key = lambda x: (your_dict [x] ['descargas'], your_dict [x] ['date'])) –

+0

Hola, estoy obteniendo un error 'TypeError: tipo de insayable:' dict ' 'al llamar como:' ordenados (d.items(), clave = lambda x: (d [x] ['descargas'], d [x] ['fecha'])) ', donde d es igual al diccionario en el OP. Por favor, si alguien conoce el problema, hágamelo saber. Gracias – ChickenFeet

0
a = {'KEY1':{'name':'google','date':20100701,'downloads':0}, 
'KEY2':{'name':'chrome','date':20071010,'downloads':0}, 
'KEY3':{'name':'python','date':20100710,'downloads':100}} 


z = a.items() 

z.sort(key=lambda x: (x[1]['downloads'], x[1]['date'])) 
+0

'z.sort (clave = lambda x: (x [1] ['descargas'], x [1] ['fecha']))' devuelve None. ¿Alguna idea de por qué? – ChickenFeet

2

Mi otra respuesta era incorrecta (como lo son la mayoría de las respuestas aquí)

sorted_keys = sorted((key for key in outer_dict if outer_dict[key]['downloads']), 
        key=lambda x: (outer_dict[key]['downloads'], 
            outer_dict[key]['downloads']) 
        reverse=True) 

sorted_keys += sorted((key for key in outer_dict if not outer_dict[key]['downloads']), 
         key=lambda x: outer_dict[key]['date']) 

Esto creará una lista con los elementos que se han descargado en orden descendente en la parte delantera de la misma y el resto de los elementos que no se han descargado ordenados por fecha después de los que tienen.

Pero en realidad, la última parte de Eli Courtwrights answer es la mejor.

+0

Er, ¿por qué estás 'import' -ing' operator' y nunca lo estás usando? – Amber

+0

@Amber porque pensé que iba a hacer otra cosa y luego comenzó a llover. Yo estaba en un apuro. Dentro ahora – aaronasterling

6

Puede pasar una función key a sorted que devuelve una tupla que contiene las dos cosas que desea ordenar. Suponiendo que su diccionario grande se llama d:

def keyfunc(tup): 
    key, d = tup 
    return d["downloads"], d["date"] 

items = sorted(d.items(), key = keyfunc) 

Usted puede hacer esto con un lambda, si lo prefiere, pero esto es probablemente más clara. Aquí está el código basado en lambda equivalentes:

items = sorted(d.items(), key = lambda tup: (tup[1]["downloads"], tup[1]["date"])) 

Por cierto, ya que ha mencionado que quería para ordenar por "descargas" en primer lugar, los dos ejemplos anteriores especie de descarga de acuerdo con el recuento en orden ascendente. Sin embargo, a partir del contexto que suena es posible que desee ordenar en orden decreciente de descargas, en cuyo caso se diría

return -d["downloads"], d["date"] 

en su keyfunc. Si quería algo así como la clasificación en orden ascendente de los números de descarga que no son cero, y luego tener todos los registros de descarga-cero después de eso, se podría decir algo así como

return (-d["downloads"] or sys.maxint), d["date"] 
+1

Intenté ambas cosas, pero en lugar de una lista de claves obtuve una lista de tuplas. Puedo usar esto también, pero es una complejidad innecesaria. '[('KEY3', {'nombre': 'python', 'fecha': 20100710, 'descargas': 100})]' –

Cuestiones relacionadas