2009-08-11 29 views
7

Tôi đang viết một số Trình so sánh tùy chỉnh và tôi muốn chúng đẩy các mục rỗng vào cuối danh sách, bất kể tôi sắp xếp tăng dần hay giảm dần. Chiến lược hay mô hình tốt để tiếp cận điều này là gì?Cách tổng quát tốt đẹp để sắp xếp giá trị rỗng vào đáy, bất kể?

sửa soạn trước:

  • Đơn giản chỉ cần viết tăng dần và giảm dần bộ so sánh riêng biệt, chia sẻ đang nếu có thể
  • Đại biểu rỗng xử lý đến lớp khác , hoặc bằng cách ném một NPE hoặc bằng cách gọi nó một cách rõ ràng
  • Bao gồm một cờ tăng dần và đặt logic điều kiện trong đó để điều hướng xung quanh các dấu trống
  • Bao gồm các trình so sánh thông thường trong một lớp học không xử lý

Bất kỳ chiến lược nào khác? Tôi muốn nghe về bất kỳ trải nghiệm nào với các cách tiếp cận khác nhau và mọi cạm bẫy cho các chiến lược khác nhau.

Trả lời

5

Tùy chọn cuối cùng thu hút tôi rất nhiều. Các bộ so sánh thực sự tuyệt vời khi kết hợp với nhau. Đặc biệt, bạn cũng có thể muốn viết một số ReverseComparator cũng như NullWrappingComparator.


EDIT: Bạn không phải tự viết mã này. Nếu bạn nhìn vào lớp Ordering trong Google Collections Library bạn sẽ tìm thấy điều này và tất cả các loại bánh kẹo khác :)


EDIT: Đi sâu vào chi tiết hơn để hiển thị những gì tôi muốn nói về ReverseComparator ...

Một từ cảnh báo - trong việc thực hiện một ReverseComparator, đảo ngược thứ tự của các đối số thay vì phủ nhận kết quả, vì nếu không Integer.MIN_VALUE sẽ bị "đảo ngược" cho chính nó.

Vì vậy, thực hiện này là sai (giả sử original là so sánh để đảo ngược):

public int compare(T x, T y) 
{ 
    return -original.compare(x, y); 
} 

nhưng điều này là đúng:

public int compare(T x, T y) 
{ 
    return original.compare(y, x); 
} 

Lý do là chúng tôi luôn muốn đảo ngược so sánh, nhưng nếu original.compare(x, y) trả về int.MIN_VALUE, thì trình so sánh không hợp lệ sẽ cũng trả lại int.MIN_VALUE, điều này không chính xác. Điều này là do tài sản vui nhộn mà int.MIN_VALUE == -int.MIN_VALUE.

+0

Tôi đồng ý với tất cả câu trả lời của bạn ngoại trừ việc phủ nhận kết quả so sánh; Tôi sẽ khá không vui nếu tôi phát hiện ra rằng một Comparator đã thực hiện so sánh số nguyên bằng cách sử dụng phép trừ, vì phương pháp đó có rất nhiều cạm bẫy. – jprete

+1

@jprete: Tôi nghĩ bạn đã hiểu lầm tôi. Tôi sẽ chỉnh sửa. –

+1

Tôi chấp nhận câu trả lời này vì tham chiếu đến lớp Thứ tự của Bộ sưu tập của Google - mã đã được chứng minh hiện tại là giải pháp tốt nhất. Cũng cho cảnh báo về Integer.MIN_VALUE. Nhưng tôi đánh giá cao mã @ dfa, bên dưới và muốn tôi có thể chấp nhận cả hai câu trả lời. –

10

Tôi đồng ý với Jon Skeet (thật dễ dàng :).Tôi cố gắng để thực hiện một rất đơn giản decorator:

class NullComparators { 

    static <T> Comparator<T> atEnd(final Comparator<T> comparator) { 
     return new Comparator<T>() { 

      public int compare(T o1, T o2) { 
       if (o1 == null && o2 == null) { 
        return 0; 
       } 

       if (o1 == null) { 
        return 1; 
       } 

       if (o2 == null) { 
        return -1; 
       } 

       return comparator.compare(o1, o2); 
      } 
     }; 
    } 

    static <T> Comparator<T> atBeginning(final Comparator<T> comparator) { 
     return Collections.reverseOrder(atEnd(comparator)); 
    } 
} 

cho một Comparator:

Comparator<String> wrapMe = new Comparator<String>() { 
     public int compare(String o1, String o2) { 
      return o1.compareTo(o2); 
     } 
}; 

và một số dữ liệu thử nghiệm:

List<String> strings = Arrays.asList(null, "aaa", null, "bbb", "ccc", null); 

bạn có thể sắp xếp với null ở cuối:

Collections.sort(strings, NullComparators.atEnd(wrapMe)); 
 
[aaa, bbb, ccc, null, null, null] 

hoặc ngay từ đầu:

Collections.sort(strings, NullComparators.atBeginning(wrapMe)); 
 
[null, null, null, ccc, bbb, aaa] 
+3

Rất đẹp! Cảm ơn bạn. Có lý do nào để không trả về 0 nếu cả hai đối số là null? Tôi biết rằng hành vi null không hoàn toàn giống như hành vi không null, và nói rằng hai null là bằng nhau là có vấn đề - nhưng nó ít có vấn đề để nói rằng một vượt quá khác? –

+2

@Carl: Chính xác điểm mà tôi vừa tạo cho bài đăng của bạn :) Một Comparator * nên * trả về 0 hoặc ném một ngoại lệ khi truyền hai null, nếu không nó không tuân theo giao diện giao diện. –

5

Theo dõi về câu trả lời của DFA - những gì tôi muốn là null loại ở phần cuối mà không ảnh hưởng thứ tự của các phi null. Vì vậy, tôi muốn một cái gì đó nhiều hơn dọc theo dòng này:

public class NullComparatorsTest extends TestCase { 
    Comparator<String> forward = new Comparator<String>() { 
            public int compare(String a, String b) { 
             return a.compareTo(b); 
            } 
           }; 

    public void testIt() throws Exception { 
     List<String> strings = Arrays.asList(null, "aaa", null, "bbb", "ccc", null); 
     Collections.sort(strings, NullComparators.atEnd(forward)); 
     assertEquals("[aaa, bbb, ccc, null, null, null]", strings.toString()); 
     Collections.sort(strings, NullComparators.atBeginning(forward)); 
     assertEquals("[null, null, null, aaa, bbb, ccc]", strings.toString()); 
    } 
} 

public class NullComparators { 
    public static <T> Comparator<T> atEnd(final Comparator<T> comparator) { 
     return new Comparator<T>() { 
      public int compare(T a, T b) { 
       if (a == null && b == null) 
        return 0; 
       if (a == null) 
        return 1; 
       if (b == null) 
        return -1; 
       return comparator.compare(a, b); 
      } 
     }; 
    } 

    public static <T> Comparator<T> atBeginning(final Comparator<T> comparator) { 
     return new Comparator<T>() { 
      public int compare(T a, T b) { 
       if (a == null && b == null) 
        return 0; 
       if (a == null) 
        return -1; 
       if (b == null) 
        return 1; 
       return comparator.compare(a, b); 
      } 
     }; 
    } 
} 

Tín dụng đầy đủ để dfa, mặc dù - đây chỉ là một sửa đổi nhỏ công việc của mình.

+1

Một vấn đề: bạn không trả về 0 khi so sánh hai giá trị rỗng. –

+0

Cảm ơn; chỉnh sửa với hiệu chỉnh. –

2

Bạn luôn có thể sử dụng NullComparator từ bộ sưu tập commons. Nó dài hơn Google Collections.

3

Trong Java 8, bạn có thể sử dụng các phương pháp tĩnh Comparator.nullsLastComparator.nullsFirst tĩnh để có nhiều bộ so sánh không thân thiện hơn. Giả sử bạn có một lớp Fruit như sau:

public class Fruit { 
    private final String name; 
    private final Integer size; 

    // Constructor and Getters 
} 

Nếu bạn muốn sắp xếp một loạt các loại trái cây bằng kích thước của chúng và đặt null s ở cuối:

List<Fruit> fruits = asList(null, new Fruit("Orange", 25), new Fruit("Kiwi", 5)); 

Bạn chỉ có thể viết:

Collections.sort(fruits, Comparator.nullsLast(Comparator.comparingInt(Fruit::getSize))); 

Và kết quả sẽ là:

[Fruit{name='Kiwi', size=5}, Fruit{name='Orange', size=25}, null] 
Các vấn đề liên quan