web-dev-qa-db-ja.com

このArrayListを希望の方法で並べ替えるにはどうすればよいですか?

ArrayListの簡単なソートプログラムを次に示します。

ArrayList<String> list = new ArrayList<String>();

list.add("1_Update");
list.add("11_Add");
list.add("12_Delete");
list.add("2_Create");

Collections.sort(list);
for (String str : list) {
  System.out.println(str.toString());
}

このプログラムの出力は次のように期待していました。

1_Update
2_Create
11_Add
12_Delete

しかし、このプログラムを実行すると、次のような出力が得られます。

11_Add
12_Delete
1_Update
2_Create

これはなぜですか、また、予想される出力に示されているようにArrayListをソートするにはどうすればよいですか?

36
Pahari Chora

カスタムコンパレータを作成できます。

Collections.sort(list, new Comparator<String>() {
    public int compare(String a, String b) {
        return Integer.signum(fixString(a) - fixString(b));
    }
    private int fixString(String in) {
        return Integer.parseInt(in.substring(0, in.indexOf('_')));
    }
});
70
nsayer

このタイプのデータを文字列としてソートすると、数字を含む文字自体が比較されます。たとえば、「1」で始まる文字列はすべて一緒になります。したがって、順序はこれと同様になります...

1 10100 2 20200

文字列の先頭にある可変長の数字など、文字列のサブセットに意味を割り当てるソートを「実現」することはありません。数字を文字列として並べ替える場合、最大数をカバーするために必要なだけゼロを左にパディングすると役立ちますが、例のようにデータを制御しない場合、実際には問題を解決しません。その場合、並べ替えは...

001 002 010 020 100 200

8
Jim Blake

数値ではなくテキスト(アルファベット順)としてソートされます。これを回避するには、nsayerの回答で提案されているカスタムコンパレータを実装します。

6
Halvard

辞書編集の比較を行っています。各文字列の最初の文字を並べ替えて比較します。次に、同じ最初の文字を持つ2番目の文字列を比較します。 「_」文字を数字と比較すると、8> 7やa> 9のような単一の数字よりも値が大きくなります。数値比較ではなく文字比較を行っていることに注意してください。

スクリプト名を変更するよりも優れた独自のカスタムソートルーティングを実装する方法があります。

スクリプト名の変更がオプションの場合、これにより他のスクリプトツールの使用が許可される場合があります。 1つの形式は

 01_create_table.sql 
 02_create_index.sql 
 11_assign_privileges.sql 

最初の2桁を2文字に保つことにより、辞書式比較が機能します。

3
QSmienk

Collections.sort()メソッドのドキュメントによると:

要素の自然順序付けに従って、指定されたリストを昇順でソートします。

これは、文字列の場合、アルファベット順にリストを取得することを意味します。文字列11_assign_privileges.sqlは文字列1_create_table.sqlの前にあり、12_07_insert_static_data.sqlは1_create_table.sqlなどの前にあります。したがって、プログラムは正常に動作しています。

2

Collection.sort()を任意にソートするには、次を使用できます。

Collections.sort(List list, Comparator c)  

次に、文字列を分割し、最初に数値に基づいてソートし、次に残りに基づいてソートするComparatorを実装します。

0
Kris

説明は、文字列が文字列としてソートされているということであるとすでに指摘しており、数はすでに自然順序の文字列比較に注意を向けています。このコンパレータを自分で記述するのは素晴らしい練習であり、テスト駆動開発を実践する絶好の機会であると付け加えます。 Code CampでTDDのデモに使用しました。スライドとコードは こちら です。

0
Carl Manaster

IComparableインターフェイスを追加してから、特定のプロパティで並べ替えることができます。たとえば、店舗のアイテムのコレクションがある場合は、価格やカテゴリなどで並べ替えることができます。名前で並べ替える場合の例を次に示します。

arrayListがアイテムのnameプロパティによってどのようにソートされるかに注意してください。 IComparableを追加しない場合、sortメソッドを使用するとエラーがスローされます。

enter image description here

static void Main(string[] args)
    {
        ArrayList items = new ArrayList();
        items.Add(new Item("book", 12.32));
        items.Add(new Item("cd", 16.32));
        items.Add(new Item("bed", 124.2));
        items.Add(new Item("TV", 12.32));

        items.Sort();

        foreach (Item temp in items)
            Console.WriteLine("Name:{0} Price:{1}", temp.name, temp.price);
        Console.Read();            
    }


    class Item: IComparable
    {
        public string name;
        public double price;

        public Item(string _name, double _price)
        {
            this.name = _name;
            this.price = _price;
        }

        public int CompareTo(object obj)
        {   
            //note that I use the name property I may use a different one
            int temp = this.name.CompareTo(((Item)obj).name);
            return temp;
        }
    }
0
Tono Nam

文字列はアルファベット順にソートされ、アンダースコア文字は数字の文字の後にあるためです。目的の結果を得るには、「自然順序」を実装するコンパレータを提供する必要があります。

0
Matej

文字列比較アルゴリズムは、一度に各文字を比較します。 12の前にソートされます。後に1または2が続くことは問題ではありません。

したがって、1002の前にソートされます。この動作が望ましくない場合は、このケースを処理する比較アルゴリズムが必要です。

0
Zifre

他の人が述べたように、要素はデフォルトでアルファベット順にソートされます。解決策は、具体的なJava.util.Comparatorクラスを定義し、それをsortメソッドの2番目の引数として渡すことです。コンパレータは、文字列の先頭の整数を解析して比較する必要があります。

0
jiggy