web-dev-qa-db-ja.com

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

簡単なクラスがあります

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

およびList<ActiveAlarm> con。 timeStarted、次にtimeEndedで昇順で並べ替える方法は?誰でも助けることができますか?私はC++で汎用アルゴリズムとオーバーロード演算子<を知っていますが、Javaは初めてです。

128
Jennifer

ActiveAlarmComparable<ActiveAlarm>を実装させるか、Comparator<ActiveAlarm>を別のクラスに実装します。次に呼び出します:

Collections.sort(list);

または

Collections.sort(list, comparator);

一般に、単一の「自然な」並べ替え順序がある場合は Comparable<T> を実装することをお勧めします...それ以外の場合(ifhappen特定の順序で並べ替えたいが、同じように簡単に別の順序で並べ替えたい場合) 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;
  }
}
135
Jon Skeet

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以降では、単純にラムダ式を使用してComparatorインスタンスを表すことができます。

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

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を持つレコードの場合)。

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

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

編集:.thenComparing()関数を指定してくれたLukas Ederに感謝します。

38
John Fowler

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

1。コンパレータの使用:複数の場所でソートロジックを使用する必要がある場合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);
19
Jagadeesh

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

collectionObjec.sort(comparator_lamda)またはコンパレータ.comparing(CollectionType :: getterOfProperty)

コード:

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

または

ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))
4
Karthikeyan
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
Kal

Java8以降では、これは ComparatorLambda 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
Mathias G.

グアバの 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();
            }});

Javaでは、静的なCollections.sortメソッドを使用する必要があります。 CompanyRoleオブジェクトのリストの例を次に示します。最初はbeginで、次にendでソートされています。自分のオブジェクトに簡単に適応できます。

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;
            }
        }
    });
}
1
Richard H

前述のとおり、次の方法で並べ替えることができます。

  • オブジェクトにComparableを実装させる
  • または、ComparatorCollections.sortに渡す

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

0
Alireza Fattahi

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

0
Liv

Collections.sort を使用して、独自の Comparator<ActiveAlarm> を渡すことができます。

0
MarcoS