Javaでソートされたコレクション


161

私はJavaの初心者です。Javaでソートされたリストを維持するために使用できる/使用すべきコレクションを提案してください。私が試してみましたMapSet、彼らは私が探していたものではありませんでした。

回答:


187

これは非常に遅くなりますが、JDKには、ソートされたリストを作成するためだけのクラスがあります。これは、名前が付けられています(他のSorted*インターフェースとは多少関係がありません)java.util.PriorityQueueComparable<?>を使用して、またはを使用してソートできますComparator

Listソートを使用した場合との違いCollections.sort(...)は、ヒープデータ構造を使用することで、O(log(n))挿入パフォーマンスで常に部分的な順序を維持するのに対し、ソートでの挿入はArrayListO(n)になることです(つまり、バイナリ検索と移動を使用して)。

ただし、とは異なりListPriorityQueueはインデックス付きアクセス(get(5))をサポートしていません。ヒープ内のアイテムにアクセスする唯一の方法は、アイテムを一度に1つずつ取り出すことです(したがって、名前PriorityQueue)。


4
この回答は、JDKで機能を備えた唯一のコレクションを指し示しているため、より多くの賛成意見に値します
nimcap

96
Javadocから:「メソッドiterator()で提供されるイテレータは、特定の順序でPriorityQueueの要素をトラバースすることは保証されていません。」
ChristofferHammarström11年

10
@giraff:優先度キューはまさにそれであり、優先度キューを維持するのに非常に効率的なデータ構造です。前面からポーリングして、並べ替えられた順序でデータアイテムを取得できます。ただし、ヒープは要素の全体的な順序を内部的に維持しないため(これが効率的な理由です)、ポーリング操作を実行せずに要素に順番にアクセスする方法はありません。
Martin Probst、2011

2
@chrispyそれは、データ構造で実現したいことによって少し異なります。ヒープは、アイテムのリストを維持し、後で順序付けられた方法でそれらを取得する効率的な方法です。イテレータを使用しても機能しませんが、そこからポーリングすると、データが順番に取得されます。検索は破壊的ですが、多くの場合それでも問題ありません。だからこの答えは良いと思います。
Martin Probst 2012年

4
@MartinProbstそのコレクションを予想どおりの順序で反復できないことを明確に示して、回答を修正してください。多くの人が言ったように、これは非常に誤解を招くものです!
ホルヘガルバン2014

53

TreeMapとTreeSetは、ソートされた順序でコンテンツを繰り返します。または、ArrayListを使用し、Collections.sort()を使用して並べ替えることもできます。これらのクラスはすべてjava.utilにあります


27
ただし、これには2つの大きな欠点があります。1つ目は、セットに重複を設定できないことです。2つ目は、リストとCollections.sort()を使用すると、常に巨大なリストをソートする傾向があり、パフォーマンスが低下することです。確かに「ダーティ」フラグを使用できますが、まったく同じではありません。
ジェイチ

これは、dupliactesを許可し、セット(バランスバイナリツリー)と同様のパフォーマンスを提供するJavaのオプションがあるかどうかという疑問を引き起こします
mankadnandan 2017年

32

頻繁に変更するソートされたリスト(つまり、ソートされるだけでなく、複製が可能で、その要素をインデックスで効率的に参照できる構造)を維持する場合は、ArrayListを使用しますが、要素を挿入する必要がある場合、常にCollections.binarySearch()を使用して、特定の要素を追加するインデックスを決定します。後者の方法は、リストをソートされた順序に保つために挿入する必要があるインデックスを示します。


11
n個の挿入はO(n ^ 2)になります。TreeSetは、よりクリーンなコードとO(n log n)を提供します。OTOH、変更頻度が低いため、配列のバイナリ検索はより高速になり、メモリ使用量も少なくなります(GCオーバーヘッドが少なくなります)。
Tom Hawtin-2009年

コードをクリーンに保ち、重複を許可するには、ソートされた順序で値を挿入するSortedListクラスを作成するのは簡単です。
Shiny and New安宇

@ TomHawtin-tacklineで言及されている警告に対処できる場合、これは最も支持されている回答であるimoよりも優れた回答です。イテレータが期待どおりに機能することは、ほとんどの場合に重要です。
DuneCat

ちなみに、トムはその特定の動作に正解です。ツリーセットは、より効率的な変更を提供します。しかし、ツリーセットはリストではなく(要素がインデックスによって参照され、重複を許可するという厳密な意味で)、ポスターはリストが必要だと述べました。
Neil Coffey

ニールさん、ありがとうございます。
vikingsteve 2014

31

Google GuavaのTreeMultisetクラスを使用します。グアバには素晴らしいコレクションAPIがあります。

ソートされた順序を維持するListの実装を提供することに関する1つの問題は、add()メソッドのJavaDocsで行われる約束です。


マルチセットの提案に対する
称賛

5
+1はList常にa が最後に追加する要件に言及します。
Roland Illig

2
TreeMultiSetは依然として重複する要素を許可しないことに注意してください(compareTo()が0を返す要素であり、equals()チェックは返しません)。同じ優先度のアイテムを複数追加する傾向がある場合、最初に追加されたアイテムの数が増えるだけで、他のアイテムは破棄され、効果的なカウントバッグの実装になります。
2012


12

いくつかのオプションがあります。複製が不要で、挿入するオブジェクトが同等である場合は、TreeSetをお勧めします。

これを行うには、Collectionsクラスの静的メソッドを使用することもできます。

詳細については、Collections#sort(java.util.List)およびTreeSetを参照してください。



5

私が行ったことは、すべてのメソッドが委任された内部インスタンスを持つリストを実装することです。

 public class ContactList implements List<Contact>, Serializable {
    private static final long serialVersionUID = -1862666454644475565L;
    private final List<Contact> list;

public ContactList() {
    super();
    this.list = new ArrayList<Contact>();
}

public ContactList(List<Contact> list) {
    super();
    //copy and order list
    List<Contact>aux= new ArrayList(list);
    Collections.sort(aux);

    this.list = aux;
}

public void clear() {
    list.clear();
}

public boolean contains(Object object) {
    return list.contains(object);
}

その後、要素が存在しない場合に適切な位置に挿入する、または存在する場合に備えて置き換える新しいメソッド「putOrdered」を実装しました。

public void putOrdered(Contact contact) {
    int index=Collections.binarySearch(this.list,contact);
    if(index<0){
        index= -(index+1);
        list.add(index, contact);
    }else{
        list.set(index, contact);
    }
}

繰り返し要素を許可する場合は、代わりにaddOrdered(または両方)を実装します。

public void addOrdered(Contact contact) {
    int index=Collections.binarySearch(this.list,contact);
    if(index<0){
        index= -(index+1);
    }
    list.add(index, contact);
}

挿入を避けたい場合は、「add」および「set」メソッドでサポートされていない操作例外をスローすることもできます。

public boolean add(Contact object) {
    throw new UnsupportedOperationException("Use putOrdered instead");
}

...また、ListIteratorメソッドは内部リストを変更する可能性があるため、注意が必要です。この場合、内部リストのコピーを返すか、再び例外をスローできます。

public ListIterator<Contact> listIterator() {
    return (new ArrayList<Contact>(list)).listIterator();
}

問題は、これがList契約に違反していることです。多分それだけを実装する方が良いでしょうCollection。そして、ContactListソートされている場合は、より効率的にcontains()使用binarySearchすることもできます。
Marcono1234

5

希望どおりにソートされたリストを実装する最も効率的な方法は、次のようにインデックス付け可能なスキップリストを実装することです:Wikipedia:Indexable skiplist。O(log(n))での挿入/削除が可能になり、同時にインデックス付きアクセスが可能になります。また、重複も許可されます。

スキップリストはかなり興味深いものであり、過小評価されているデータ構造です。残念ながら、Javaベースライブラリにはインデックス付きのスキップリスト実装はありませんが、オープンソース実装の1つを使用するか、自分で実装できます。ConcurrentSkipListSetConcurrentSkipListMapのような定期的なスキップリストの実装があります。


4

TreeSetは重複を許可しないため機能せず、特定の位置で要素をフェッチするメソッドを提供しません。PriorityQueueは、リストの基本的な要件である特定の位置で要素をフェッチできないため、機能しません。重複が必要でない限り、O(logn)挿入時間でJavaでソートされたリストを維持するには、独自のアルゴリズムを実装する必要があると思います。多分解決策は、キーが項目のサブクラスであるTreeMapを使用して、equalsメソッドをオーバーライドし、重複が許可されるようにすることです。


4

LambdaJの使用

Java 8の以前のバージョンを使用している場合は、LambdaJでこれらのタスクを解決してみることができます。ここで見つけることができます:http : //code.google.com/p/lambdaj/

ここに例があります:

反復ソート

List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
Collections.sort(sortedByAgePersons, new Comparator<Person>() {
        public int compare(Person p1, Person p2) {
           return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
        }
}); 

LambdaJで並べ替え

List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge()); 

もちろん、このような美しさはパフォーマンスに影響します(平均2倍)が、もっと読みやすいコードを見つけることができますか?

ラムダ式を使用してJava 8で並べ替え

Collections.sort(persons, (p1, p2) -> p1.getAge().compareTo(p2.getAge()));
//or
persons.sort((p1, p2) -> p1.getAge().compareTo(p2.getAge()));

Java 8ラムダ式を使用した最後の例では、どのようにソートを逆にできますか?
Rajat Shah

1
@RajatShahちょうどあなたができると思います-(p1.getAge().compareTo(p2.getAge()))
フェデリコ

@RajatShahは喜んでお手伝いします
フェデリコピアッツァ

2

PriorityQueueの問題は、単純な配列によってバックアップされ、要素を順番に取得するロジックが「queue [2 * n + 1]とqueue [2 *(n + 1)]」によって実行されることです。頭から引っ張るだけならうまくいきますが、ある時点で.toArrayを呼び出そうとすると役に立たなくなります。

私はcom.google.common.collect.TreeMultimapを使用してこの問題を回避していますが、Orderingにラップされた値のカスタムコンパレータを提供しており、0を返すことはありません。

例。ダブルの場合:

private static final Ordering<Double> NoEqualOrder = Ordering.from(new Comparator<Double>() {

    @Override
    public int compare(Double d1, Double d2)
    {
        if (d1 < d2) {
            return -1;
        }
        else {
            return 1;
        }
    }
});

この方法で、.toArray()を呼び出すときに値を順番に取得し、重複も取得します。


1

あなたが欲しいのは二分探索木です。ソートされた順序を維持しながら、検索、削除、挿入に対数アクセスを提供します(縮退したツリーがない限り、線形です)。実装は非常に簡単で、Listインターフェースを実装することもできますが、インデックスアクセスは複雑になります。

2番目の方法は、ArrayListを作成してから、バブルソートを実装することです。一度に1つの要素を挿入または削除するため、挿入と削除のアクセス時間は線形です。検索は対数であり、インデックスアクセス定数です(LinkedListでは時間が異なる場合があります)。必要なコードは、5、たぶん6行のバブルソートだけです。


1

ArraylistとTreemapを使用できます。繰り返し値も必要だと言ったので、TreeSetは使用できませんが、ソートもされていますが、コンパレーターを定義する必要があります。


1

SetにはTreeSetを使用できます。TreeSetは、その特定のオブジェクトのComparableに渡された自然順序付けまたは任意の並べ替え順序に基づいて要素を順序付けします。マップにはTreeMapを使用します。TreeMapはキーのソートを提供します。オブジェクトをキーとしてTreeMapに追加するには、そのクラスが比較可能なインターフェースを実装する必要があります。このインターフェースは、ソート順の定義を含むcompare to()メソッドを実装することを強制します。 http://techmastertutorial.in/java-collection-impl.html



0

TreeSetソートされた順序で要素を与えるwhichを使用します。またはを使用Collection.sort()した外部ソートに使用しComparator()ます。


TreeSetは要素の複製を許可しません。それが望ましい機能である場合もあれば、そうでない場合もあります。OPを考えると、私はノーのために推測、セットを試してみました
USR-ローカルΕΨΗΕΛΩΝ

意地悪なことはしないでください。TreeMapも指摘してください。docs.oracle.com/ javase
HaakonLøtveitApr

0
import java.util.TreeSet;

public class Ass3 {
    TreeSet<String>str=new TreeSet<String>();
    str.add("dog");
    str.add("doonkey");
    str.add("rat");
    str.add("rabbit");
    str.add("elephant");
    System.out.println(str);    
}

0

Java 8 Comparatorでは、リストを並べ替える場合、世界で最も人口の多い10の都市を以下に示します。時間で報告されるように、名前で並べ替えます。大阪、日本。...メキシコシティ、メキシコ。... 中国、北京。...ブラジル、サンパウロ。...ムンバイ、インド。... 中国、上海。...インド、デリー。... 東京、日本。

 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;

public class SortCityList {

    /*
     * Here are the 10 most populated cities in the world and we want to sort it by
     * name, as reported by Time. Osaka, Japan. ... Mexico City, Mexico. ...
     * Beijing, China. ... São Paulo, Brazil. ... Mumbai, India. ... Shanghai,
     * China. ... Delhi, India. ... Tokyo, Japan.
     */
    public static void main(String[] args) {
        List<String> cities = Arrays.asList("Osaka", "Mexico City", "São Paulo", "Mumbai", "Shanghai", "Delhi",
                "Tokyo");
        System.out.println("Before Sorting List is:-");
        System.out.println(cities);
        System.out.println("--------------------------------");

        System.out.println("After Use of List sort(String.CASE_INSENSITIVE_ORDER) & Sorting List is:-");
        cities.sort(String.CASE_INSENSITIVE_ORDER);
        System.out.println(cities);
        System.out.println("--------------------------------");
        System.out.println("After Use of List sort(Comparator.naturalOrder()) & Sorting List is:-");
        cities.sort(Comparator.naturalOrder());
        System.out.println(cities);

    }

}

0

ユーザー定義の基準に従ってArrayListをソートします。

モデルクラス

 class Student 
 { 
     int rollno; 
     String name, address; 

     public Student(int rollno, String name, String address) 
     { 
         this.rollno = rollno; 
         this.name = name; 
         this.address = address; 
     }   

     public String toString() 
     { 
         return this.rollno + " " + this.name + " " + this.address; 
     } 
 } 

分類クラス

 class Sortbyroll implements Comparator<Student> 
 {         
     public int compare(Student a, Student b) 
     { 
         return a.rollno - b.rollno; 
     } 
 } 

メインクラス

 class Main 
 { 
     public static void main (String[] args) 
     { 
         ArrayList<Student> ar = new ArrayList<Student>(); 
         ar.add(new Student(111, "bbbb", "london")); 
         ar.add(new Student(131, "aaaa", "nyc")); 
         ar.add(new Student(121, "cccc", "jaipur")); 

         System.out.println("Unsorted"); 
         for (int i=0; i<ar.size(); i++) 
             System.out.println(ar.get(i)); 

         Collections.sort(ar, new Sortbyroll()); 

         System.out.println("\nSorted by rollno"); 
         for (int i=0; i<ar.size(); i++) 
             System.out.println(ar.get(i)); 
     } 
 } 

出力

 Unsorted
 111 bbbb london
 131 aaaa nyc
 121 cccc jaipur

 Sorted by rollno
 111 bbbb london
 121 cccc jaipur
 131 aaaa nyc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.