Función de comparación personalizada en python3

Quiero ordenar los puntos en el sistema de coordenadas 2D por su distancia al origen (0,0) en orden creciente. Encontré esto y probé algo, pero aun así no pude obtener el resultado deseado.

Aquí está mi código:

from functools import cmp_to_key def my_comp(point1, point2): return point1[0]*point1[0] + point1[1]*point1[1] < point2[0]*point2[0] + point2[1]*point2[1] points = [ [3.1, 4.1], [0.9, 0.8], [1.0, 1.0] ] sorted(points, key=cmp_to_key(my_comp)) print(points) 

Resultado:

 [[3.1, 4.1], [0.9, 0.8], [1.0, 1.0]] 

Esperado:

 [[0.9, 0.8], [1.0, 1.0], [3.1, 4.1]] 

1) Se supone que su función my_cmp() devuelve uno de los tres valores (+, – o 0 según la comparación), pero solo devuelve dos (Verdadero y Falso).

2) Usted ingnore el valor de retorno de sorted() . sorted() no modifica su argumento, devuelve una copia ordenada de él.

3) No utilice las funciones de cmp. Son difíciles de describir y de implementar. En su lugar, utilice las funciones clave.

Qué tal si:

 def my_key(point1): return point1[0]*point1[0] + point1[1]*point1[1] points = [ [3.1, 4.1], [0.9, 0.8], [1.0, 1.0] ] points = sorted(points, key=my_key) print(points) assert points == [ [0.9, 0.8], [1.0, 1.0], [3.1, 4.1] ] 

¿Hace esto lo que quieres?

 sorted_points = sorted(points, key=lambda p: p[0]*p[0] + p[1]*p[1]) 

Otra cosa a tener en cuenta en su código original es que la ordenada no ordena la lista en su lugar, crea una nueva lista que está ordenada. Así que cuando lo hagas

 points = [3,2,1] sorted(points) print(points) 

Aparecerá que su código no ha ordenado nada porque está imprimiendo la lista original, no la ordenada recién creada. Puede realizar una clasificación en el lugar como tal.

 points = [3,2,1] points.sort() print(points) 

Parece que estás pasando por algunos aros extra aquí. Tienes una cantidad que ya es una llave perfecta. En lugar de solo usarlo, define un comparador que vuelve a calcular y compara dos de estas cantidades para cada par de objetos, y luego convierte ese comparador de nuevo en una clave.

Esto parece muy ineficiente. ¿Por qué no solo definir una función clave simple y usarla directamente?

 def distance_from_origin_squared(point): return point[0]**2 + point[1]**2 points = sorted(points, key=distance_from_origin_squared) 

Tenga en cuenta que la sorted no funciona en el lugar, por lo que debe guardarla en algún lugar. Reemplazo del nombre original si está bien. Si desea una ordenación in situ, use list.sort en list.sort lugar:

 points.sort(key=distance_from_origin_squared) 

Desde un punto de vista práctico, las claves ofrecen una serie de ventajas sobre los comparadores. Por un lado, una función clave solo necesita ser llamada una vez por elemento, mientras que un comparador se llama O(nlog(n)) veces. Por supuesto, las claves se comparan O(nlog(n)) veces, pero la comparación suele ser mucho más sencilla, ya que los valores de interés se calculan por adelantado.

La principal dificultad que proviene de C (en mi caso) es comprender la idea de que las claves no tienen que ser enteros únicos, como se muestra en los ejemplos. Las claves pueden ser de cualquier tipo que defina claramente el operador < (o > ). La comparación lexicográfica de cadenas, listas y tuplas hace que sea muy fácil hervir un comparador en cadena complejo a una tecla que es solo una breve secuencia de valores.

Estás confundiendo los argumentos key y cmp . Una función cmp acepta dos argumentos y devuelve -1 , 0 o 1 . Una función key devuelve un valor proxy que se utilizará para ordenar la lista. Se eliminó cmp como argumento para sorted en Python 3.