2010-11-22 11 views
31

Napisałem następujący kod:Komparator z łóżkiem typu

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

Gdybym powiedzmy mają dwa podwójne numery, 3.2 - 3.1, różnica powinna być 0.1. Jednak kiedy rzutuję liczbę na int, różnica kończy się jako 0, co nie jest poprawne.

Dlatego potrzebuję compare(), aby zwrócić podwójne, nie int. Problem polega na tym, że moje pole getX jest podwójne. Jak mogę rozwiązać ten problem?

Odpowiedz

59

nie potrzeba, aby powrócić double.

Interfejs Comparator służy do ustalenia kolejności porównywanych elementów. Posiadanie pól, które używają double, jest nieistotne dla tego zamówienia.

Twój kod jest w porządku.

Niestety, myliłem się, czytając ponownie pytanie, to jest to, czego potrzebujesz:

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

Myślę, że to się nie powiedzie z 'NaN' i' * _INFINITY' – Jerome

7

Metoda compare powinna zwrócić wartość int. Jest to numer, który jest albo:

  • Mniej niż zero, jeśli pierwsza wartość jest mniej niż drugi;
  • Równa na zero, jeśli dwie wartości to równa;
  • Większy niż zero, jeśli pierwsza wartość to większa niż niż druga;

Nie trzeba zwrócić double. Musisz musi zwrócić int w celu implementacji interfejsu Comparator. Musisz tylko zwrócić poprawną int, zgodnie z zasadami opisanymi powyżej.

Nie można po prostu rzucać z int, tak, jak pan powiedział, różnica 0,1 spowoduje 0. Można po prostu to zrobić:

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; 
} 

Ale ponieważ porównanie wartości zmiennoprzecinkowych jest zawsze kłopotliwe, należy porównać w pewnym zakresie (patrz this question), coś takiego:

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

dzięki za pełną odpowiedź! Dostaję całość! Nigdy nie zapomnę takiego w ten sposób – user472221

78

Proponuję użyć wbudowanego metodę Double.compare(). Jeśli potrzebujesz zakresu, w którym podwójne wartości są równe, możesz najpierw użyć tego polecenia.

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

lub

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

Problem z wykorzystaniem < i> jest NaN zwraca fałsz w obu przypadkach powodując możliwie niezgodny obsługi. na przykład NaN jest zdefiniowany jako nie będący równym cokolwiek, nawet samemu w rozwiązaniach @ suihock i @ Martinho, jeśli któraś z wartości to NaN, metoda zwróci 0 za każdym razem, co oznacza, że ​​NaN jest równe wszystkiemu.

+3

Java 7 dodała compare() dla spójności "Long" i "Integer". –

+1

Oto [link do kodu źródłowego] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/Double.java#lnmr- 999) z 'Double.compare()', aby zobaczyć, w jaki sposób obsługuje 'NaN'. – xdhmoore

+0

Prawdopodobnie możesz też użyć 'Math.signum', jeśli chcesz nieco inaczej działać na NaN. – xdhmoore

0

Cóż, przed konwersją na liczbę całkowitą można pomnożyć te podwójne wartości przez odpowiedni współczynnik, np. w twoim przypadku, ponieważ jest to tylko jedno miejsce dziesiętne, więc 10 byłoby dobrym czynnikiem;

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

Ta odpowiedź działa tylko w pewnych okolicznościach. To znaczy. gdy pomnożenie przez 10 spowoduje, że podwójne wartości staną się liczbą całkowitą. – robjwilkins

+0

@robjwilkins: Czy mógłbyś wyjaśnić, że w takim przypadku ta metoda wyboru odpowiedniego czynnika nie zadziałałaby? – HasnainMamdani

+0

Nie działa w przypadku, gdy getY zwraca liczbę, która nie może być pomnożona przez 10, aby uzyskać liczbę całkowitą. Na przykład, jeśli getY zwróci 3.2111, to rozwiązanie nie będzie działać. Ponieważ getY zwraca wartość double, jest całkowicie możliwe, że zwróci 3,2111. To rozwiązanie jest zatem bardzo ograniczone i istnieje znacznie lepsza alternatywa. – robjwilkins

2

prostu chcą rozwinąć Peter Lawrey odpowiedź na JDK 8, jeśli zrobisz to tak:

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

Można zdefiniować to porównanie za pomocą wyrażenia lambda dość łatwo

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

Co więcej, można użyć odwołania do elementu podobnego do tego:

Double::compare 
+1

Podoba mi się użycie lambda w tej odpowiedzi, jest to bardzo dobra sugestia. Nie rozumiem jednak, jak możesz użyć referencji dla członków? Czy możesz podać przykład? dzięki – robjwilkins

6

Ponieważ Java 1.8 można również użyć

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

Korzystając Double.compare(/**double value 1*/, /**double value 2*/); z nowym komparatora dla podwójnej wartości klasy modelu.

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

Pamiętaj, że możesz odwrócić kolejność sortowania za pomocą Double.compare (d2, d1) w przeciwieństwie do Double.compare (d1, d2). To oczywiste, ale wciąż. – Asu

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