2010-11-22 9 views
31

He escrito el siguiente código:Comparador de doble tipo

public class NewClass2 implements Comparator<Point> 
{ 
    public int compare(Point p1, Point p2) 
    { 
     return (int)(p1.getY() - p2.getY()); 
    } 
} 

Si digamos que tiene dos números dobles, 3.2 - 3.1, la diferencia debe ser 0.1. Sin embargo, cuando lanzo el número a un int, la diferencia termina en 0, lo que no es correcto.

Por lo tanto, necesito compare() para devolver un doble, no un int. El problema es que mi campo getX es doble. ¿Como puedó resolver esté problema?

Respuesta

59

no es necesario volver double.

La interfaz Comparator se utiliza para establecer un orden de los elementos que se comparan. Tener campos que usan double es irrelevante para este orden.

Su código es correcto.

Lo siento, estaba equivocado, la lectura de la pregunta de nuevo, esto es lo que necesita:

public class NewClass2 implements Comparator<Point> { 
    public int compare(Point p1, Point p2) { 
     if (p1.getY() < p2.getY()) return -1; 
     if (p1.getY() > p2.getY()) return 1; 
     return 0; 
    }  
} 
+4

Creo que esto no funcionará con 'NaN' y' * _INFINITY' – Jerome

7

El método compare debe devolver un int. Es un número que es ya sea:

  • Menos que cero, si el primer valor es menos que la segunda;
  • Igual a cero, si los dos valores son igual;
  • Mayor que cero, si el primer valor es mayor que el segundo;

Usted no necesita para devolver un double. Usted debe devolver un int para implementar la interfaz Comparator. Solo tiene que devolver el int correcto, de acuerdo con las reglas que describí anteriormente.

No se le puede echar de int, ya que, como usted ha dicho, una diferencia de 0,1 dará lugar a 0. Usted puede simplemente hacer esto:

public int compare(Point p1, Point p2) 
{ 
    double delta= p1.getY() - p2.getY(); 
    if(delta > 0) return 1; 
    if(delta < 0) return -1; 
    return 0; 
} 

Pero ya que la comparación de los valores de punto flotante es siempre problemático, debe comparar dentro de un cierto rango (ver this question), algo como esto:

public int compare(Point p1, Point p2) 
{ 
    double delta = p1.getY() - p2.getY(); 
    if(delta > 0.00001) return 1; 
    if(delta < -0.00001) return -1; 
    return 0; 
} 
+0

gracias por la respuesta completa! ¡Yo obtengo el todo! Nunca lo olvido de esta manera – user472221

78

le sugiero que utilice el método incorporado Double.compare(). Si necesita un rango para que los valores dobles sean iguales, puede usar chcek para eso primero.

return Double.compare(p1.getY(), p2.gety()); 

o

if(Math.abs(p1.getY()-p2.getY()) < ERR) return 0;  
return Double.compare(p1.getY(), p2.gety()); 

El problema con el uso < y> es que NaN volverá falsa en ambos casos resulta en un manejo posiblemente inconsistente. p.ej. NaN se define como no ser igual a nada, incluso a sí mismo, sin embargo en las soluciones de @suhock y @ Martinho, si cualquiera de los valores es NaN, el método devolverá 0 cada vez, lo que implica que NaN es igual a todo.

+3

Java 7 se agregó compare() para la coherencia 'Long' y' Integer'. –

+1

Aquí hay un [enlace al código fuente] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/Double.java#lnmr- 999) de 'Double.compare()' para ver cómo maneja 'NaN'. – xdhmoore

+0

Probablemente también podría usar 'Math.signum' si desea un comportamiento ligeramente diferente en NaNs. – xdhmoore

0

Bueno, podría multiplicar esos valores dobles por un factor apropiado antes de convertirlos en enteros, por ejemplo. en su caso, dado que es un solo decimal, entonces 10 sería un buen factor;

return (int)(p1.getY()*10 - p2.getY()*10); 
+0

Esta respuesta solo funciona en ciertas circunstancias. Es decir. al multiplicar por 10, los valores dobles se convertirán en un número entero. – robjwilkins

+0

@robjwilkins: ¿Podría aclarar eso en cuyo caso este método de elegir un factor apropiado no funcionaría? – HasnainMamdani

+0

No funciona en el caso en que getY devuelve un número que no se puede multiplicar por 10 para obtener un número entero. Por ejemplo, si getY devuelve 3.2111, entonces esta solución no funcionará. Como getY devuelve un doble, es completamente factible que devuelva 3.2111. Esta solución es, por lo tanto, muy limitada, y hay alternativas mucho mejores. – robjwilkins

2

sólo quiero ampliar respuesta de Pedro Lawrey en JDK 8, si lo haces de esta manera:

public class NewClass2 implements Comparator<Point> { 
    public int compare(Point p1, Point p2) { 
     return Double.compare(p1.getY(), p2.gety()); 
    }  
} 

se podría definir este comparador utilizando una expresión lambda con bastante facilidad

(Point p1,Point p2) -> Double.compare(p1.getY(), p2.gety()) 

Mejor aún, podría utilizar una referencia de miembro como esta:

Double::compare 
+1

Me gusta el uso de la lambda en esta respuesta, es una muy buena sugerencia. Aunque no entiendo cómo podrías usar una referencia de miembro. Podría dar un ejemplo? gracias – robjwilkins

6

Desde Java 1.8 también se puede utilizar

Comparator.comparingDouble(p -> p.getY()) 
1

Uso Double.compare(/**double value 1*/, /**double value 2*/); con un nuevo Comparador de su valor doble clase del modelo.

public static List<MyModel> sortByDouble(List<MyModel> modelList) { 
     Collections.sort(modelList, new Comparator<MyModel>() { 
      @Override 
      public int compare(MyModels1, MyModels2) { 
       double s1Distance = Double.parseDouble(!TextUtils.isEmpty(s1.distance) ? s1.distance : "0"); 
       double s2Distance = Double.parseDouble(!TextUtils.isEmpty(s2.distance) ? s2.distance : "0"); 
       return Double.compare(s1Distance, s2Distance); 
      } 
     }); 
     return modelList; 
    } 
+0

Tenga en cuenta que puede revertir el orden de clasificación utilizando Double.compare (d2, d1) en lugar de Double.compare (d1, d2). Obvio, pero aún – Asu

0
Double min = Arrays.stream(myArray).min(Double::compare).get(); 
Cuestiones relacionadas