オブジェクトのリストをいくつかのプロパティでソートする方法


144

簡単なクラスがあります

public class ActiveAlarm {
    public long timeStarted;
    public long timeEnded;
    private String name = "";
    private String description = "";
    private String event;
    private boolean live = false;
}

そしてList<ActiveAlarm>詐欺。どのによって昇順にソートするtimeStartedことで、その後、timeEnded?誰か助けてもらえますか?C ++では汎用アルゴリズムとオーバーロード演算子<を知っていますが、Javaは初めてです。


この投稿の@Yishaiによる回答は、コンパレータチェーンを利用したカスタムソートおよびグループ化ソート(複数の引数)のための列挙型のエレガントな使用法を示しています。
gunalmel 2012

回答:


140

作るのいずれかをActiveAlarm実施Comparable<ActiveAlarm>または実施Comparator<ActiveAlarm>別々のクラスに。次に電話してください:

Collections.sort(list);

または

Collections.sort(list, comparator);

一般に、Comparable<T>「自然な」並べ替え順序が1つある場合は実装することをお勧めします。それ以外の場合(たまたま特定の順序で並べ替えたいが、簡単に別の順序で並べ替えたい場合)、実装することをお勧めしますComparator<T>。この特定の状況は、正直に言うとどちらの方向にも進む可能性がありますが、私はおそらくより柔軟なComparator<T>オプションを使い続けるでしょう

編集:サンプル実装:

public class AlarmByTimesComparer implements Comparator<ActiveAlarm> {
  @Override
  public int compare(ActiveAlarm x, ActiveAlarm y) {
    // TODO: Handle null x or y values
    int startComparison = compare(x.timeStarted, y.timeStarted);
    return startComparison != 0 ? startComparison
                                : compare(x.timeEnded, y.timeEnded);
  }

  // I don't know why this isn't in Long...
  private static int compare(long a, long b) {
    return a < b ? -1
         : a > b ? 1
         : 0;
  }
}

1
そのcompare()関数はLongにはありません。実装がさらに簡単だからです。return a-b;
ペーパークレーン、2014年

5
@papercrane:いいえ、オーバーフローの理由で失敗します。考えてくださいa = Long.MIN_VALUE, b = 1
Jon Skeet、2014年

3
API 19(KitKat)現在、Longには.compare
Martin Marconciniが2016

123

使用する Comparator

例えば:

class Score {

    private String name;
    private List<Integer> scores;
    // +accessor methods
}

    Collections.sort(scores, new Comparator<Score>() {

        public int compare(Score o1, Score o2) {
            // compare two instance of `Score` and return `int` as result.
            return o2.getScores().get(0).compareTo(o1.getScores().get(0));
        }
    });

Java 8以降では、ラムダ式を使用してコンパレータインスタンスを表すことができます。

Collections.sort(scores, (s1, s2) -> { /* compute and return int */ });

1
何をしcompareTo()ますか?それはどこから来たのですか?どこで定義する必要がありますか?
Asqiir 2017

1
@AsqiirはgetScores()のためのゲッターであるscoresですList<Integer>。するとgetScores().get(0)Integerオブジェクトを取得します。メソッドIntegerはすでにcompareTo(anotherInteger)実装されているため、定義する必要はありません。
walen

get(0)とは何ですか?
Ali Khaki

1
ありがとうは魅力のように機能します(私は.get(0)部分なしで使用しています)。どうすれば順序を逆にできますか?

51

JAVA 8以上の回答(ラムダ式の使用)

Java 8では、これをさらに簡単にするためにLambda式が導入されました。すべての足場を持つComparator()オブジェクトを作成する代わりに、次のように簡略化できます(オブジェクトを例として使用)。

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted);

またはさらに短い:

Collections.sort(list, Comparator.comparingInt(ActiveAlarm ::getterMethod));

この1つのステートメントは次と同等です。

Collections.sort(list, new Comparator<ActiveAlarm>() {
    @Override
    public int compare(ActiveAlarm a1, ActiveAlarm a2) {
        return a1.timeStarted - a2.timeStarted;
    }
});

Lambda式は、コードの関連部分(メソッドシグネチャと返されるもの)を配置するだけでよいと考えてください。

あなたの質問の別の部分は、複数のフィールドと比較する方法でした。Lambda式でこれを行うには、.thenComparing()関数を使用して2つの比較を1つに効果的に組み合わせることができます。

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted             
       .thenComparing ((ActiveAlarm a1, ActiveAlarm a2) -> a1.timeEnded-a2.timeEnded)
);

上記のコードは、リストを最初にでソートし、timeStarted次にtimeEnded(同じレコードを持つレコードについて)timeStarted)。

最後に、「長い」または「int」のプリミティブを比較するのは簡単です。一方から他方を差し引くだけです。オブジェクト(「Long」または「String」)を比較する場合は、組み込みの比較を使用することをお勧めします。例:

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.name.compareTo(a2.name) );

編集:.thenComparing()機能するように指示してくれたLukas Ederに感謝します。


4
新しいJava 8 APIに感謝するかもしれませんComparator.comparing().thenComparing()...
Lukas Eder

1
違いを返すことに注意してください。オーバーフローが発生した場合、間違った結果が得られる可能性があります。
krzychu 2018年

2
これは、簡単なソート方法であるIMHOです。これも、明確な自然順序がない場合を想定しています。またCollections、もう呼び出す必要はありません。リストに直接呼び出すことができます。例:myList.sort(Comparator.comparing(Address::getZipCode).thenComparing(Compartor.comparing(Address::getStreetName));
CeePlusPlus

20

次の2つの方法のいずれかでリストをソートできます。

1.コンパレータの使用:複数の場所でソートロジックを使用する必要がある場合単一の場所でソートロジックを使用する場合は、次のように匿名の内部クラスを作成するか、コンパレータを抽出して複数の場所で使用できます。

  Collections.sort(arrayList, new Comparator<ActiveAlarm>() {
        public int compare(ActiveAlarm o1, ActiveAlarm o2) {
            //Sorts by 'TimeStarted' property
            return o1.getTimeStarted()<o2.getTimeStarted()?-1:o1.getTimeStarted()>o2.getTimeStarted()?1:doSecodaryOrderSort(o1,o2);
        }

        //If 'TimeStarted' property is equal sorts by 'TimeEnded' property
        public int doSecodaryOrderSort(ActiveAlarm o1,ActiveAlarm o2) {
            return o1.getTimeEnded()<o2.getTimeEnded()?-1:o1.getTimeEnded()>o2.getTimeEnded()?1:0;
        }
    });

「long」の代わりに「Long」を使用できた場合、プロパティのnullチェックを行うことができます。

2. Comparable(自然順序付け)の使用:ソートアルゴリズムが常に1つのプロパティに固執する場合:「Comparable」を実装するクラスを記述し、「compareTo」メソッドを以下のようにオーバーライドします

class ActiveAlarm implements Comparable<ActiveAlarm>{

public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;

public ActiveAlarm(long timeStarted,long timeEnded) {
    this.timeStarted=timeStarted;
    this.timeEnded=timeEnded;
}

public long getTimeStarted() {
    return timeStarted;
}

public long getTimeEnded() {
    return timeEnded;
}

public int compareTo(ActiveAlarm o) {
    return timeStarted<o.getTimeStarted()?-1:timeStarted>o.getTimeStarted()?1:doSecodaryOrderSort(o);
}

public int doSecodaryOrderSort(ActiveAlarm o) {
    return timeEnded<o.getTimeEnded()?-1:timeEnded>o.getTimeEnded()?1:0;
}

}

自然順序付けに基づいて並べ替えるsortメソッドを呼び出す

Collections.sort(list);

7

java8 +では、次のように1行で記述できます。

collectionObjec.sort(comparator_lamda) または comparator.comparing(CollectionType::getterOfProperty)

コード:

ListOfActiveAlarmObj.sort((a,b->a.getTimeStarted().compareTo(b.getTimeStarted())))
 

または

ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))

5
public class ActiveAlarm implements Comparable<ActiveAlarm> {
    public long timeStarted;
    public long timeEnded;
    private String name = "";
    private String description = "";
    private String event;
    private boolean live = false;

    public int compareTo(ActiveAlarm a) {
        if ( this.timeStarted > a.timeStarted )
            return 1;
        else if ( this.timeStarted < a.timeStarted )
            return -1;
        else {
             if ( this.timeEnded > a.timeEnded )
                 return 1;
             else
                 return -1;
        }
 }

それはあなたに大まかな考えを与えるはずです。それが完了したらCollections.sort()、リストを呼び出すことができます。


4

Java8ので、これも、クリーナーの組み合わせを使用して行うことができますComparatorし、Lambda expressions

例えば:

class Student{

    private String name;
    private List<Score> scores;

    // +accessor methods
}

class Score {

    private int grade;
    // +accessor methods
}

    Collections.sort(student.getScores(), Comparator.comparing(Score::getGrade);

2

グアバのComparisonChain

Collections.sort(list, new Comparator<ActiveAlarm>(){
            @Override
            public int compare(ActiveAlarm a1, ActiveAlarm a2) {
                 return ComparisonChain.start()
                       .compare(a1.timestarted, a2.timestarted)
                       //...
                       .compare(a1.timeEnded, a1.timeEnded).result();
            }});


1

Javaでは、静的Collections.sortメソッドを使用する必要があります。以下は、最初に始まり、次に終わりでソートされたCompanyRoleオブジェクトのリストの例です。自分のオブジェクトに簡単に適応できます。

private static void order(List<TextComponent> roles) {

    Collections.sort(roles, new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            int x1 = ((CompanyRole) o1).getBegin();
            int x2 = ((CompanyRole) o2).getBegin();

            if (x1 != x2) {
                return x1 - x2;
            } else {
                int y1 = ((CompanyRole) o1).getEnd();
                int y2 = ((CompanyRole) o2).getEnd();
                return y2 - y1;
            }
        }
    });
}

0

Collections.sort()を呼び出して、オブジェクトのさまざまなプロパティを比較するために記述する必要があるコンパレータを渡すことができます。


0

前述のように、次でソートできます。

  • オブジェクトを実装する Comparable
  • またはパスComparatorCollections.sort

両方を実行すると、Comparableは無視されてComparator使用されます。これは、Comparable個々のユースケースに独自の実装がある一方で、値オブジェクトが、値オブジェクトにとって最も合理的なソートである独自の論理を持つことを助けます 。

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