2011-03-06 25 views
34

Sé que hay varias preguntas llamadas así, pero parece que no puedo obtener sus respuestas para trabajar.Ordenar lista de la lista con la función de comparación personalizada en Python

Tengo una lista de listas, 50 veces 5 elementos. Ahora quiero ordenar esta lista aplicando una función de comparación personalizada para cada elemento. Esta función calcula la aptitud de la lista por la cual se ordenarán los elementos. He creado dos funciones, comparar y fitness:

def compare(item1, item2): 
    return (fitness(item1) < fitness(item2)) 

y

def fitness(item): 
    return item[0]+item[1]+item[2]+item[3]+item[4] 

Entonces traté de llamar por:

sorted(mylist, cmp=compare) 

o

sorted(mylist, key=fitness) 

o

sorted(mylist, cmp=compare, key=fitness) 

o

sorted(mylist, cmp=lambda x,y: compare(x,y)) 

También probé list.sort() con los mismos parámetros. Pero en cualquier caso las funciones no obtienen una lista como argumento sino un None. No tengo idea de por qué es, que proviene principalmente de C++, esto contradice cualquier idea de una función de devolución de llamada para mí. ¿Cómo puedo ordenar estas listas con una función personalizada?

Editar Encontré mi error. En la cadena que crea la lista original, una función no devolvió nada, pero se utilizó el valor de retorno. Lo siento por la molestia

+2

Mostrar código, lo que espera y lo que se obtiene. – delnan

+2

Tenga en cuenta que su función 'compare' es incorrecta, ya que solo devuelve True o False, y no distingue entre' item1' y 'item2' siendo igual y' item1' siendo mayor que 'item2'. La forma correcta de escribir 'compare' sería devolver' cmp (fitness (item1), fitness (item2)) '. Pero usar 'clave' es mejor. – jchl

Respuesta

23
>>> l = [list(range(i, i+4)) for i in range(10,1,-1)] 
>>> l 
[[10, 11, 12, 13], [9, 10, 11, 12], [8, 9, 10, 11], [7, 8, 9, 10], [6, 7, 8, 9], [5, 6, 7, 8], [4, 5, 6, 7], [3, 4, 5, 6], [2, 3, 4, 5]] 
>>> sorted(l, key=sum) 
[[2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8], [6, 7, 8, 9], [7, 8, 9, 10], [8, 9, 10, 11], [9, 10, 11, 12], [10, 11, 12, 13]] 

Lo anterior funciona. ¿Estás haciendo algo diferente?

Observe que la función de su clave es solo sum; no hay necesidad de escribirlo explícitamente.

+1

Tiene toda la razón, algún otro código ha causado el error, gracias. Y gracias de nuevo, al menos ahora tengo un ejemplo que usa una función en lugar de una expresión lambda como valor clave. No pude encontrar uno cuando busqué una solución antes. – DaClown

51

Además, su función de comparación es incorrecta. Necesita devolver -1, 0 o 1, no un booleano como lo tiene. La función de comparación correcta sería:

def compare(item1, item2): 
    if fitness(item1) < fitness(item2): 
     return -1 
    elif fitness(item1) > fitness(item2): 
     return 1 
    else: 
     return 0 
+21

o simplemente, 'aptitud de retorno (item1) - aptitud (item2)'. La función de comparación no tiene que devolver -1 o 1, sino simplemente un número negativo o positivo (o cero). Ref: http://docs.python.org/2/library/stdtypes.html#mutable-sequence-types – LarsH

+6

'ordenados (miLista, clave = lambda x: -fitness (x))' –

+3

o 'ordenados (miLista, key = fitness, reverse = True) ' – orange

3

Es necesario modificar ligeramente su función compare y utilizar functools.cmp_to_key pasarlo a sorted. Código de ejemplo:

import functools 

lst = [list(range(i, i+5)) for i in range(5, 1, -1)] 

def fitness(item): 
    return item[0]+item[1]+item[2]+item[3]+item[4] 
def compare(item1, item2): 
    return fitness(item1) - fitness(item2) 

sorted(lst, key=functools.cmp_to_key(compare)) 

Salida:

[[2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8], [5, 6, 7, 8, 9]] 

Obras :)

Cuestiones relacionadas