Custom Sorting ในแบบที่ A มาก่อน a และ B มาก่อน b


11

ฉันมีรายการสีดังนี้:

ชมพู, ฟ้า, แดง, น้ำเงิน, เทา, เขียว, ม่วง, ดำ ... ฯลฯ

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

มีการดำเนินการระดับกลางบางอย่างเช่นการกรองสีผลไม้ตอนนี้ฉันเหลือผลลัพธ์การกรองที่ฉันต้องการเรียงลำดับ:

สีน้ำเงิน, ดำ, น้ำเงิน, เทา, เขียว, ชมพู, ม่วง, แดง

ฉันเหนื่อย :

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

มันไม่ทำงานตามที่คาดไว้

ผลลัพธ์มีดังต่อไปนี้:

ดำ, น้ำเงิน, น้ำเงิน, เขียว, เทา, ชมพู, ม่วง, แดง

ฉันต้องการสิ่งต่อไปนี้:

สีน้ำเงิน, ดำ, น้ำเงิน, เทา, เขียว, ชมพู, ม่วง, แดง


2
ไม่ควรดำมาก่อนสีน้ำเงินและเขียวต่อเทา
Ravindra Ranwala

3
aก่อนหน้านี้uดังนั้นผลลัพธ์จึงถูกต้อง
Jens

2
@RawindraRanwala, Blue 's Bเป็นเมืองหลวง แต่backของbไม่ใช่
Vishwa Ratna

2
ฉันพยายาม แต่มันไม่ได้ให้คำสั่งเฉพาะนี้ มันให้[black, Blue, blue, green, Grey, Pink, purple, Red]@ chrylis-onstrike-
Ravindra Ranwala

2
หากคุณต้องการให้ปลอกเงินทุนมาก่อนปลอกที่ต่ำกว่าการเพิกเฉยปลอกเป็นสิ่งสุดท้ายที่คุณต้องการ
Teepeemm

คำตอบ:


8

โซลูชันของฉันคือใช้การเรียงลำดับในสองขั้นตอนโดยใช้Comparator.thenComparing()วิธี

ก่อนอื่นให้เปรียบเทียบสตริงโดยใช้ตัวพิมพ์ใหญ่ตัวพิมพ์เล็กเท่านั้น ดังนั้นกลุ่มที่มีตัวอักษรตัวแรกเหมือนกัน จากนั้นในขั้นตอนที่สองจะใช้การเรียงลำดับตัวอักษรปกติเพื่อจัดเรียงกลุ่มย่อยที่ไม่เรียงลำดับ

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

อาจจะยังสามารถปรับให้เหมาะสม แต่ก็ให้ผลลัพธ์ที่ต้องการ:

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


Comparatorทำให้การแก้ไขเพื่อให้สามารถอ่านของ แต่ใช่สิ่งนี้จะถือว่าเป็นการเปรียบเทียบอักขระตัวแรกของ String ที่ OP ไม่ได้เน้นมากเช่นกัน
Naman

8

คุณสามารถใช้RuleBasedCollatorเพื่อกำหนดกฎของคุณเอง

ตัวอย่างของกฎที่กำหนดเอง :

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

กฎข้างต้นถูกถอดรหัสเนื่องจากตัวพิมพ์ใหญ่และตัวพิมพ์เล็กCจะปรากฏก่อนหน้าตัวพิมพ์ใหญ่และตัวพิมพ์เล็กBเมื่อเปรียบเทียบสตริง

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

เอาท์พุท:

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

แก้ไข:แทนที่จะเขียนcustomRulesด้วยมือคุณสามารถใช้โค้ดด้านล่างเพื่อสร้างรหัสได้

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

2
การสร้างString customRulesสามารถเป็นไปโดยอัตโนมัติด้วยIntStream:IntStream.range('a', 'z' + 1) .mapToObj(Character::toString) .flatMap(ch -> Stream.of("<", ch.toUpperCase(), "<", ch)) .collect(Collectors.joining(""))
lczapski

@lczapski อย่างใด.mapToObj(Character::toString)จะไม่ได้รับการแก้ไขฉันเดาว่าคุณจำเป็นต้องใช้.mapToObj(c -> Character.toString((char) c))
Vishwa Ratna

mapToObj(Character::toString)ใช้งานได้กับ Java 11 หรือใหม่กว่าเท่านั้น
Holger

@ โฮลค์โอเคฉันลองใช้ระบบของฉัน (JDK-8) และmapToObj(Character::toString)ไม่ได้รับการแก้ไข แต่ฉันชอบความคิดดังนั้นฉันเลยลงเอยด้วยการคัดเลือกนักแสดง.mapToObj(c -> Character.toString((char) c))
Vishwa Ratna

3
ฉันต้องการIntStream.rangeClosed('a', 'z').flatMap(c -> IntStream.of(c,Character.toUpperCase(c))) .mapToObj(c -> Character.toString((char)c)) .collect(Collectors.joining("<", "<", ""));
Holger

0

คุณต้องการวิธีการที่จะทำการเปรียบเทียบแบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่สำหรับตัวอักษรแต่ละตัวก่อนจากนั้นถ้ามีการเปรียบเทียบให้ทำการเปรียบเทียบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่กับตัวอักษรแต่ละตัว:

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

Stream.sortedจากนั้นคุณสามารถส่งผ่านวิธีนี้เพื่อ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.