Java 8 Comparator, Làm thế nào để sắp xếp List
Bạn muốn sắp xếp một List của bạn, hãy tìm hiểu bạn sẽ có nhiều cách để có thể có được danh sách mình mong muốn. Trong bài viết này chúng ta sẽ thấy vài ví dụ về cách sắp xếp một danh sách trong Java 8 Sắp xếp một List theo Alphabetically List<String> cities = Arrays.asList( ...
Bạn muốn sắp xếp một List của bạn, hãy tìm hiểu bạn sẽ có nhiều cách để có thể có được danh sách mình mong muốn. Trong bài viết này chúng ta sẽ thấy vài ví dụ về cách sắp xếp một danh sách trong Java 8
Sắp xếp một List theo Alphabetically
List<String> cities = Arrays.asList( "Milan", "london", "San Francisco", "Tokyo", "New Delhi" ); System.out.println(cities); //[Milan, london, San Francisco, Tokyo, New Delhi] cities.sort(String.CASE_INSENSITIVE_ORDER); System.out.println(cities); //[london, Milan, New Delhi, San Francisco, Tokyo] cities.sort(Comparator.naturalOrder()); System.out.println(cities); //[Milan, New Delhi, San Francisco, Tokyo, london]
Trên bạn sẽ thấy, tôi đã cố tình viết chữ 「l」thường, nếu trong so sánh CASE_INSENSITIVE_ORDER thì sẽ không phân biệt chữ hoa chữ thường, Nhưng kiểu naturalOrder() thì có phần biệt chữ hoa chữ thường Về cơ bản trong java 7 thì chúng ta có: Collections.sort() đẻ sắp xếp một List Nhưng trong java 8 thì chúng ta sử dụng List.sort() và comparator đế sắp xếp một List
Sắp xếp một List các số nguyên
List<Integer> numbers = Arrays.asList(6, 2, 1, 4, 9); System.out.println(numbers); //[6, 2, 1, 4, 9] numbers.sort(Comparator.naturalOrder()); System.out.println(numbers); //[1, 2, 4, 6, 9]
Sắp xếp một danh sách bởi thuộc tính kiểu String
Giả sử chúng ta có một danh sách Movies , chúng ta muốn sắp xếp theo title. Chúng ta có thể sử dụng Comparator.comparing() và truyền vào biến là thuộc tính title để thực hiện sắp xếp
List<Movie> movies = Arrays.asList( new Movie("Lord of the rings"), new Movie("Back to the future"), new Movie("Carlito's way"), new Movie("Pulp fiction")); movies.sort(Comparator.comparing(Movie::getTitle)); movies.forEach(System.out::println); // Output /* Movie{title='Back to the future'} Movie{title='Carlito's way'} Movie{title='Lord of the rings'} Movie{title='Pulp fiction'} */
Nhìn trông source có vẻ đơn giản vì không sử dụng so sánh trung gian nào, nhưng thực sự thì bạn vào source code implement của Comparator.comparing() bạn sẽ thấy
return (Comparator<T> & Serializable) (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
Về cơ bản trước ở java 7 thì bạn phải tạo Comparator để so sanh, nhưng lên java 8 có nhiều trường hợp so sánh đơn giản đã được tích hợp sẵn
Sắp xếp List bởi thuộc tính kiểu double
Bằng cách tương tự, chúng ta có thể sử dụng Comparator.comparingDouble() để so sánh giá trị doublt. Trong ví dụ sau chúng ta muốn sắp xếp danh sách các bộ phim theo thứ tự Rating từ cao đến thấp
List<Movie> movies = Arrays.asList( new Movie("Lord of the rings", 8.8), new Movie("Back to the future", 8.5), new Movie("Carlito's way", 7.9), new Movie("Pulp fiction", 8.9)); movies.sort(Comparator.comparingDouble(Movie::getRating) .reversed()); movies.forEach(System.out::println);
Chúng ta sử dụng hàm reversed để làm đảo ngược thứ tự sắp xếp thông thường từ thấp đến cao -> Từ cao đến thấp, bên cạnh sử dụng so sanh theo double bạn cũng có thể sử dụng so sánh theo kiểu Int hoặc Long bằng cách sử dụng comparingInt(0 hoặc comparingLong()
Sắp xếp danh sách bởi Custom Comparator
Trong các ví dụ trước chúng ta đều dùng kiểu mặc định của java 8 mà không định nghĩa kiểu Comparator, trong ví dụ sau chúng ta muốn sắp xếp các bộ phim theo dấu Starred, nghĩa là những bộ phim có Start sẽ đứng ở trên
List<Movie> movies = Arrays.asList( new Movie("Lord of the rings", 8.8, true), new Movie("Back to the future", 8.5, false), new Movie("Carlito's way", 7.9, true), new Movie("Pulp fiction", 8.9, false)); // Định nghĩa một kiểu comparator movies.sort(new Comparator<Movie>() { @Override public int compare(Movie m1, Movie m2) { if(m1.getStarred() == m2.getStarred()){ return 0; } return m1.getStarred() ? -1 : 1; } }); movies.forEach(System.out::println); // Output /* Movie{starred=true, title='Lord of the rings', rating=8.8} Movie{starred=true, title='Carlito's way', rating=7.9} Movie{starred=false, title='Back to the future', rating=8.5} Movie{starred=false, title='Pulp fiction', rating=8.9} */
Trên là cách thông thường, chúng tao có thể sử dụng lamda với một class ẩn danh để viết
movies.sort((m1, m2) -> { if(m1.getStarred() == m2.getStarred()){ return 0; } return m1.getStarred() ? -1 : 1; });
Cũng có thể sử dụng Comparator.comparing()
movies.sort(Comparator.comparing(Movie::getStarred, (star1, star2) -> { if(star1 == star2){ return 0; } return star1 ? -1 : 1; }));
Trên là những ví dụ chỉ so sánh với một thuộc tinh, sau đây chúng ta sẽ đi đến ví dụ so sánh với danh sách các comparator
Sắp xếp List với một danh sách các comparator
List<Movie> movies = Arrays.asList( new Movie("Lord of the rings", 8.8, true), new Movie("Back to the future", 8.5, false), new Movie("Carlito's way", 7.9, true), new Movie("Pulp fiction", 8.9, false)); // Sắp xếp movies.sort(Comparator.comparing(Movie::getStarred) .reversed() .thenComparing(Comparator.comparing(Movie::getRating) .reversed()) ); movies.forEach(System.out::println); // Output /* Movie{starred=true, title='Lord of the rings', rating=8.8} Movie{starred=true, title='Carlito's way', rating=7.9} Movie{starred=false, title='Pulp fiction', rating=8.9} Movie{starred=false, title='Back to the future', rating=8.5} */
Sau khi sắp xếp bạn có được danh sách theo starred và rating theo thứ tự giảm dần
Bạn có thể sử dụng một hoặc nhiều comparator trong hàm sort để có được List mong muốn của mình
Tổng kết
Trong Java 8 bạn có thể sủ dụng 2 kiểu so sánh đó là như ở trong Java 7 hoặc sử dụng viết so sánh với Lamda để có List mình mong muốn