Aがaの前に、Bがbの前にくるカスタムソート


11

私はこのような色のリストを持っています:

ピンク、ブルー、レッド、ブルー、グレー、グリーン、パープル、ブラック... etc

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ので、結果は正しい
イェンス

2
@RavindraRanwala、BlueBは資本ですが、backbはそうではありません。
Vishwa Ratna

2
私は試しましたが、それはこの特定の順序を与えません。これは、与え[black, Blue, blue, green, Grey, Pink, purple, Red]@ chrylisが-onstrike-
ラビンドラRanwala

2
大文字と小文字を大文字の前に置く場合は、大文字と小文字を無視するのが最後です。
Teepeemm

回答:


8

私の解決策は、 Comparator.thenComparing()メソッドことです。

まず、大文字と小文字を区別しない最初の文字だけで文字列を比較します。したがって、最初の文字が同じ(どのような場合でも)グループは、これまでのところ並べ替えられていません。次に、2番目のステップで、通常のアルファベット順の並べ替えを適用して、並べ替えられていないサブグループを並べ替えます。

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。しかし、はい、これはOPがあまり強調していない文字列の最初の文字のみを比較することを前提としています。
ナマン

8

RuleBasedCollat​​orを使用して、独自のルールを定義できます。

カスタムルールの例:

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付きオートマすることができIntStreamIntStream.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

@Holger [OK]を、私は私のシステム(JDK-8)にしようと、mapToObj(Character::toString)解決されていませんでしたが、私はのようなキャスティングをやってしまうので、私はアイデアを気に入っ.mapToObj(c -> Character.toString((char) c))
Vishwaラトナ

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.