2010-11-22 25 views
31

Tôi đã viết đoạn mã sau:sánh với đôi loại

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

Nếu tôi giả sử có hai số gấp đôi, 3.2 - 3.1, sự khác biệt nên 0.1. Tuy nhiên, khi tôi truyền số này sang int, sự khác biệt kết thúc là 0, điều này không chính xác.

Do đó, tôi cần compare() để trả lại số tiền gấp đôi, không phải là số int. Vấn đề là, trường getX của tôi là gấp đôi. Làm thế nào tôi có thể giải quyết vấn đề này?

Trả lời

59

bạn không cần phải trả lại double.

Giao diện Comparator được sử dụng để thiết lập thứ tự cho các yếu tố được so sánh. Có các trường sử dụng double không liên quan đến đơn đặt hàng này.

Mã của bạn vẫn ổn.

Xin lỗi, tôi đã sai, đọc câu hỏi một lần nữa, đây là những gì bạn cần:

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

Tôi nghĩ rằng điều này sẽ thất bại với 'NaN' và' * _INFINITY' – Jerome

7

Phương thức compare phải trả lại int. Đó là một con số đó là một trong hai:

  • Ít hơn không, nếu giá trị đầu tiên là ít so với thứ hai;
  • Bằng bằng không, nếu hai giá trị là bằng;
  • Lớn hơn bằng 0, nếu giá trị đầu tiên là lớn hơn so với giây;

Bạn không cần để trả lại double. Bạn phải trả lại int để triển khai giao diện Comparator. Bạn chỉ cần trả lại đúng int, theo các quy tắc tôi đã nêu ở trên.

Bạn có thể không chỉ đơn giản là đúc từ int, như, như bạn nói, một sự khác biệt là 0,1 sẽ cho kết quả 0. Bạn chỉ có thể làm điều này:

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

Nhưng kể từ so sánh các giá trị dấu chấm động là luôn rắc rối, bạn nên so sánh trong một phạm vi nhất định (xem this question), một cái gì đó như thế này:

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

cảm ơn câu trả lời hoàn chỉnh! Tôi nhận được toàn bộ! Tôi không bao giờ quên như vậy theo cách này – user472221

78

tôi đề nghị bạn sử dụng phương pháp dựng sẵn Double.compare(). Nếu bạn cần một phạm vi cho các giá trị kép bằng nhau, bạn có thể sử dụng chcek cho giá trị đầu tiên đó.

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

hoặc

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

Vấn đề với việc sử dụng < và> là NaN sẽ trả về false trong cả hai trường hợp dẫn đến việc xử lý có thể không phù hợp. ví dụ. NaN được định nghĩa là không bằng bất cứ thứ gì, thậm chí chính nó trong các giải pháp @ suihock và @ Martinho, nếu giá trị là NaN, phương thức sẽ trả về 0 mọi lúc, ngụ ý rằng NaN bằng mọi thứ.

+3

Java 7 thêm so sánh() cho 'Long' và' Integer' nhất quán. –

+1

Đây là [liên kết tới mã nguồn] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/Double.java#lnmr- 999) của 'Double.compare()' để xem nó xử lý 'NaN' như thế nào. – xdhmoore

+0

Bạn cũng có thể sử dụng 'Math.signum' nếu bạn muốn hành vi hơi khác nhau trên NaN. – xdhmoore

0

Vâng, bạn có thể nhân các giá trị kép đó với một yếu tố thích hợp trước khi chuyển đổi thành số nguyên, ví dụ: trong trường hợp của bạn vì chỉ có một chữ số thập phân nên 10 sẽ là một yếu tố tốt;

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

Câu trả lời này chỉ hoạt động trong một số trường hợp nhất định. I E. khi nhân với 10 sẽ dẫn đến các giá trị kép trở thành một số nguyên. – robjwilkins

+0

@robjwilkins: Bạn có thể làm rõ rằng trong trường hợp này, phương pháp chọn yếu tố phù hợp này sẽ không hoạt động? – HasnainMamdani

+0

Nó không hoạt động trong trường hợp getY trả về một số không thể nhân với 10 để lấy số nguyên. Ví dụ: nếu getY trả về 3.2111 thì giải pháp này sẽ không hoạt động. Vì getY trả về gấp đôi, nó hoàn toàn khả thi để trả về 3.2111. Do đó, giải pháp này rất hạn chế và có nhiều lựa chọn thay thế tốt hơn. – robjwilkins

2

Tôi chỉ muốn mở rộng Peter Lawrey câu trả lời trên JDK 8, nếu bạn làm điều đó như thế này:

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

Bạn có thể định nghĩa so sánh này sử dụng một biểu thức lambda khá dễ dàng

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

Tốt hơn, bạn có thể sử dụng tham chiếu thành viên như sau:

Double::compare 
+1

Tôi thích việc sử dụng lambda trong câu trả lời này, đó là một gợi ý rất tốt. Tôi không hiểu làm thế nào bạn có thể sử dụng một tài liệu tham khảo thành viên mặc dù? Bạn có thể cung cấp một ví dụ? thanks – robjwilkins

6

Kể từ Java 1.8 bạn cũng có thể sử dụng

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

Sử dụng Double.compare(/**double value 1*/, /**double value 2*/); với một sánh mới cho giá trị gấp đôi mô hình lớp học của bạn.

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

Lưu ý rằng bạn có thể hoàn nguyên thứ tự sắp xếp bằng cách sử dụng Double.compare (d2, d1) thay vì Double.compare (d1, d2). Rõ ràng nhưng vẫn còn. – Asu

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