32

文字列 (SortedSet 内) のデフォルトのコンパレータに問題があります。問題は、デフォルトのコンパレータが数字を含む適切な文字列をソートしないことです。つまり、セットには次のものがあります。

room1, room2, room100

自然な順序付けは上記のようにする必要がありますが、セットには次のものがあります。

room1, room100, room2

原因はわかっているのですが、変更方法がわかりません。

4

6 に答える 6

61

数字以外のすべての文字を削除し、残りの文字を数字として比較するこのコンパレータを試してください。

Collections.sort(strings, new Comparator<String>() {
    public int compare(String o1, String o2) {
        return extractInt(o1) - extractInt(o2);
    }

    int extractInt(String s) {
        String num = s.replaceAll("\\D", "");
        // return 0 if no digits found
        return num.isEmpty() ? 0 : Integer.parseInt(num);
    }
});

ここにテストがあります:

public static void main(String[] args) throws IOException {
    List<String> strings = Arrays.asList("room1.2", "foo1.1", "foo", "room2.3", "room100.999", "room10", "room.3");

    Collections.sort(strings, new Comparator<String>() {
        public int compare(String o1, String o2) {
            return extractInt(o1) - extractInt(o2);
        }

        int extractInt(String s) {
            String num = s.replaceAll("\\D", "");
            // return 0 if no digits found
            return num.isEmpty() ? 0 : Integer.parseInt(num);
        }
    });
    System.out.println(strings);
}

出力:

[foo, room1, room2, room10, room100]

数値が小数の場合 (これも Java 8+ スタイルを示しています):

public static void main(String[] args) {
    List<String> strings = Arrays.asList("room1.2", "foo1.1", "room2.3", "room100.999", "room10", "room.3");
    Collections.sort(strings, Comparator.comparing(Application::extractDouble));
    System.out.println(strings);
}

static double extractDouble(String s) {
    String num = s.replaceAll("[^\\d.]", "");
    // return 0 if no digits found
    return num.isEmpty() ? 0 : Double.parseDouble(num);
}

結果:

[foo, room.3, foo1.1, room1.2, room2.3, room10, room100.999]
于 2012-12-20T13:51:32.607 に答える
12

@bohemianの回答を使用しました。少しだけ改善しました。これは私にとって非常にうまくいきました..

        Collections.sort(asdf, new Comparator<String>() {
            public int compare(String o1, String o2) {

                String o1StringPart = o1.replaceAll("\\d", "");
                String o2StringPart = o2.replaceAll("\\d", "");


                if(o1StringPart.equalsIgnoreCase(o2StringPart))
                {
                    return extractInt(o1) - extractInt(o2);
                }
                return o1.compareTo(o2);
            }

            int extractInt(String s) {
                String num = s.replaceAll("\\D", "");
                // return 0 if no digits found
                return num.isEmpty() ? 0 : Integer.parseInt(num);
            }
        });
于 2015-04-13T17:11:46.527 に答える
6

これを試して。文字列の先頭には常に「余裕」があると想定しています。

    List<String> list = Arrays.asList("room1", "room100", "room2");
    Collections.sort(list, new Comparator<String>()
    {
        @Override
        public int compare(String o1, String o2)
        {
            return new Integer(o1.replaceAll("room", ""))
                .compareTo(new Integer(o2.replaceAll("room", "")));
        }

    });
于 2012-12-20T13:47:13.003 に答える
2

これがそのようなソートの私のComparator実装です: (文字列は任意の文字から開始できます)

public class StringNumberComparator implements Comparator<String>{

    @Override
    public int compare(String o1, String o2) {
    int i1 = this.getRearInt(o1);
    int i2 = getLeadingInt(o2);
    String s1 = getTrailingString(o1);
    String s2 = getTrailingString(o2);

    if(i1==i2)
         return s1.compareTo(s2);
    if(i1>i2)
         return 1;
    else if(i1<i2)
            return -1;
    return 0;
    }

    private int getRearInt(String s) {
    s=s.trim();
    int i=Integer.MAX_VALUE;
    try {
             i = Integer.parseInt(s.split("[^0-9]+")[1]);
    } catch(ArrayIndexOutOfBoundsException e) {

    } catch(NumberFormatException f) {
            return i;
    }

    return i;
    }

    private String getTrailingString(String s) {
        return  s.replaceFirst("[0-9]", "");
    }
}
于 2012-12-20T13:47:42.547 に答える
0

コンパレータを実装して、それを set コンストラクタに渡すことができます。http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Comparator.htmlを参照してください。

すべての文字列が room[number] の形式である場合、「部屋」を取り除いて数字を解析し、比較することができます。
または、整数をセットに保存し、「部屋」プレフィックスを付けて印刷することもできます。

于 2012-12-20T13:46:05.697 に答える
0

怠惰な代替手段は、余分なことを何もせずに文字列コンパレーターを機能させることです (独自のコンパレーターを定義します)。次のように、文字列内の数値をゼロでパディングすることで、それを実現できます。room0001, room0002, room0100その後、デフォルトの文字列コンパレータが機能します。ただし、それに応じてパディングを調整できるように、最大​​数値を知る必要があります。

于 2012-12-20T13:56:01.497 に答える