Sắp xếp tùy chỉnh theo cách mà A đến trước a và B đến trước b


11

Tôi có một Danh sách các màu như thế này:

Hồng, xanh, đỏ, xanh dương, xám, xanh lá cây, tím, đen ...

List<String> listOfColors =  Arrays.asList("Pink", "Blue", "Red", "blue", "Grey", "green", "purple", "black");

Có một số thao tác trung gian như lọc một số màu trái cây, bây giờ tôi còn lại các kết quả được lọc mà tôi muốn sắp xếp chúng theo thứ tự:

Xanh lam, đen, xanh dương, xám, xanh lá cây, hồng, tím, đỏ

Tôi đã thử :

List<String> collect = listOfColors.stream().sorted(String::compareToIgnoreCase)
        .collect(Collectors.toList());

Nó không hoạt động như mong đợi.

Đầu ra là như sau:

đen, xanh dương, xanh dương, xanh lá cây, xám, hồng, tím, đỏ

Tôi muốn như sau:

Xanh lam, đen, xanh dương, xám, xanh lá cây, hồng, tím, đỏ


2
Không nên màu đen đến trước màu xanh và màu xanh lá cây trước màu xám?
Ravindra Ranwala

3
alà trước khi ukết quả là chính xác
Jens

2
@RavindraRanwala, Xanh 's B là vốn nhưng lại ' s b thì không.
Vishwa Ratna

2
Tôi đã thử, nhưng nó không đưa ra thứ tự cụ thể này. Nó mang lại cho [black, Blue, blue, green, Grey, Pink, purple, Red]@ chrylis-onstrike-
Ravindra Ranwala

2
Nếu bạn muốn vỏ vốn đến trước vỏ thấp hơn, thì bỏ qua vỏ là điều cuối cùng mà bạn muốn.
Teepeemm

Câu trả lời:


8

Giải pháp của tôi là sử dụng sắp xếp theo hai bước bằng Comparator.thenComparing()phương pháp.

Đầu tiên, chỉ so sánh các Chuỗi bằng trường hợp bỏ qua ký tự đầu tiên. Vì vậy, các nhóm có cùng ký tự đầu tiên (bất kể trường hợp nào) vẫn chưa được sắp xếp cho đến nay. Sau đó, trong bước thứ hai áp dụng cách sắp xếp theo thứ tự chữ cái thông thường để sắp xếp các nhóm con chưa được sắp xếp đó.

List<String> listOfColors =  Arrays.asList("Pink", "Blue", "Red", "blue", "Grey", "green", "purple", "black");
Comparator<String> comparator = Comparator.comparing(s -> 
        Character.toLowerCase(s.charAt(0)));
listOfColors.sort(comparator.thenComparing(Comparator.naturalOrder()));
System.out.println(listOfColors);

Có thể nó vẫn có thể được tối ưu hóa, nhưng nó mang lại kết quả mong muốn:

[Blue, black, blue, Grey, green, Pink, purple, Red]


Thực hiện một chỉnh sửa cho dễ đọc của Comparator. Nhưng vâng, điều này giả sử chỉ so sánh ký tự đầu tiên của Chuỗi mà OP cũng không nhấn mạnh nhiều.
Naman

8

Bạn có thể sử dụng RuleBasingCollator để xác định Quy tắc của riêng bạn.

Ví dụ về quy tắc tùy chỉnh :

String rules = "< c,C < b,B";

Quy tắc trên được giải mã vì cả chữ hoa và chữ thường Cđều xuất hiện trước cả chữ hoa và chữ thường Bkhi so sánh chuỗi.

String customRules = "<A<a<B<b<C<c<D<d<E<e<F<f<G<g<H<h<I<i<J<j<K<k<L<l<M<m<N<n<O<o<P<p<Q<q<R<r<S<s<T<t<U<u<V<v<X<x<Y<y<Z<z";
RuleBasedCollator myRuleBasedCollator = new RuleBasedCollator(customRules);
Collections.sort(listOfColors,myRuleBasedCollator);
System.out.println(listOfColors);

Đầu ra:

[Blue, black, blue, Grey, green, Pink, purple, Red]

Chỉnh sửa: Thay vì viết customRulesbằng tay, bạn có thể sử dụng mã bên dưới để tạo mã.

String a = IntStream.range('a', 'z' + 1).mapToObj(c -> Character.toString((char) c))
        .flatMap(ch -> Stream
            .of("<", ch.toUpperCase(), "<", ch)).collect(Collectors.joining(""));

2
sáng tạo String customRulescó thể là chủ nghĩa tự động với IntStream:IntStream.range('a', 'z' + 1) .mapToObj(Character::toString) .flatMap(ch -> Stream.of("<", ch.toUpperCase(), "<", ch)) .collect(Collectors.joining(""))
lczapski

@lczapski, bằng cách nào đó .mapToObj(Character::toString)sẽ không được giải quyết, tôi đoán bạn cần sử dụng.mapToObj(c -> Character.toString((char) c))
Vishwa Ratna

mapToObj(Character::toString)chỉ hoạt động trong Java 11 hoặc mới hơn.
Holger

@Holger Ok, tôi đã thử trên Hệ thống của mình (JDK-8) và mapToObj(Character::toString)không được giải quyết, nhưng tôi thích ý tưởng đó nên cuối cùng tôi đã thực hiện casting như.mapToObj(c -> Character.toString((char) c))
Vishwa Ratna

3
Tôi thíchIntStream.rangeClosed('a', 'z').flatMap(c -> IntStream.of(c,Character.toUpperCase(c))) .mapToObj(c -> Character.toString((char)c)) .collect(Collectors.joining("<", "<", ""));
Holger

0

Bạn cần một phương pháp trước tiên thực hiện so sánh không phân biệt chữ hoa chữ thường trên mỗi chữ cái, sau đó nếu có một kết quả khớp thực hiện so sánh phân biệt chữ hoa chữ thường trên mỗi chữ cái:

public static int compare(String s1, String s2)
{
    int len, i;
    if (s1.length()<s2.length()) {
        len = s1.length();
    } else {
        len = s2.length();
    }
    for (i=0;i<len;i++) {
        if (Character.toUpperCase(s1.charAt(i)) < Character.toUpperCase(s2.charAt(i))) {
            return -1;
        } else if (Character.toUpperCase(s1.charAt(i)) > Character.toUpperCase(s2.charAt(i))) {
            return 1;
        } else if (s1.charAt(i) < s2.charAt(i)) {
            return -1;
        } else if (s1.charAt(i) > s2.charAt(i)) {
            return 1;
        }
    }
    if (s1.length() < s2.length()) {
        return -1;
    } else if (s1.length() > s2.length()) {
        return 1;
    } else {
        return 0;
    }
}

Sau đó bạn có thể truyền phương pháp này cho Stream.sorted.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.