Penyortiran Ubahsuaian dengan cara bahwa A datang sebelum a dan B datang sebelum b

11

Saya memiliki Daftar warna seperti ini:

Pink, Biru, Merah, biru, Abu-abu, hijau, ungu, hitam ... dll

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

Ada beberapa operasi perantara seperti memfilter beberapa warna buah, sekarang saya dibiarkan dengan hasil yang disaring di mana saya ingin mereka diurutkan secara berurutan:

Biru, hitam, biru, abu-abu, hijau, merah muda, ungu, merah

Saya telah mencoba :

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

Itu tidak bekerja seperti yang diharapkan.

Outputnya adalah sebagai berikut:

hitam, Biru, biru, hijau, Abu-abu, Merah Muda, ungu, Merah

Saya ingin yang berikut ini:

Biru, hitam, biru, abu-abu, hijau, merah muda, ungu, merah

Vishwa Ratna
sumber
2
Bukankah seharusnya hitam datang sebelum biru dan hijau sebelum Gray?
Ravindra Ranwala
3
asebelum ujadi hasilnya benar
Jens
2
@RavindraRanwala, Biru 's B adalah modal tetapi kembali ' s b tidak.
Vishwa Ratna
2
Saya mencoba, tetapi tidak memberikan urutan khusus ini. Ini memberikan [black, Blue, blue, green, Grey, Pink, purple, Red]@ chrylis-onstrike-
Ravindra Ranwala
2
Jika Anda ingin modal casing datang sebelum casing lebih rendah, maka mengabaikan casing adalah hal terakhir yang Anda inginkan.
Teepeemm

Jawaban:

8

Solusi saya adalah menggunakan penyortiran dalam dua langkah dengan menggunakan Comparator.thenComparing()metode ini.

Pertama, bandingkan Strings hanya dengan huruf pertama yang mengabaikan case. Jadi kelompok-kelompok dengan karakter pertama yang sama (tidak peduli kasus apa) tetap tidak disortir sejauh ini. Kemudian pada langkah kedua terapkan penyortiran alfabet normal untuk mengurutkan subkelompok yang tidak disortir.

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

Mungkin masih bisa dioptimalkan, tetapi memberikan hasil yang diinginkan:

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

DanielBK
sumber
Membuat edit untuk keterbacaan Comparator. Tapi ya, ini mengasumsikan hanya membandingkan karakter pertama dari String yang tidak banyak ditekankan oleh OP.
Naman
8

Anda bisa menggunakan RuleBasedCollator untuk mendefinisikan Aturan Anda sendiri.

Contoh aturan khusus :

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

Aturan di atas diterjemahkan sebagai bahwa huruf besar dan kecil Charus muncul sebelum huruf besar dan kecil Bketika membandingkan string.

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

Keluaran:

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

Sunting: Alih-alih menulis customRulesdengan tangan, Anda dapat menggunakan kode di bawah ini untuk membuatnya.

String a = IntStream.range('a', 'z' + 1).mapToObj(c -> Character.toString((char) c))
        .flatMap(ch -> Stream
            .of("<", ch.toUpperCase(), "<", ch)).collect(Collectors.joining(""));
Vishwa Ratna
sumber
2
ciptaan String customRulesbisa otomatisme dengan IntStream:IntStream.range('a', 'z' + 1) .mapToObj(Character::toString) .flatMap(ch -> Stream.of("<", ch.toUpperCase(), "<", ch)) .collect(Collectors.joining(""))
lczapski
@lczapski, entah bagaimana .mapToObj(Character::toString)tidak akan terselesaikan, saya kira Anda perlu menggunakan.mapToObj(c -> Character.toString((char) c))
Vishwa Ratna
mapToObj(Character::toString)hanya berfungsi di Java 11 atau lebih baru.
Holger
@ Holger Ok, saya mencoba Sistem saya (JDK-8) dan mapToObj(Character::toString)tidak mendapatkan penyelesaian, tetapi saya menyukai ide itu sehingga saya akhirnya melakukan casting seperti.mapToObj(c -> Character.toString((char) c))
Vishwa Ratna
3
Saya lebih sukaIntStream.rangeClosed('a', 'z').flatMap(c -> IntStream.of(c,Character.toUpperCase(c))) .mapToObj(c -> Character.toString((char)c)) .collect(Collectors.joining("<", "<", ""));
Holger
0

Anda memerlukan metode yang pertama-tama melakukan perbandingan tidak sensitif huruf pada setiap huruf, lalu jika ada kecocokan yang melakukan perbandingan sensitif huruf pada setiap huruf:

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

Anda dapat meneruskan metode ini ke Stream.sorted.

dbush
sumber