× reversed() を付けた comparing() だけ逆順になる
list.stream()
.sorted(Comparator.comparing(Element::key1)
.thenComparing(Element::key2).reversed()
.thenComparing(Element::key3));
この場合、ソートとしては以下の形になると思っていた。
- key1 の 昇順
- key1 が同じ場合は key2 の 降順
- key2 も同じ場合は key3 の 昇順
実際は reversed() を付けた対象以前のものが逆順になるため
- key1 の 降順
- key1 が同じ場合は key2 の 降順
- key2 も同じ場合は key3 の 昇順
となる。
key1 の昇順 > key2 の降順 というソートをしたい場合は下記のようになる。
list.stream()
.sorted(Comparator.comparing(Element::key1)
.reversed() // 逆順の逆順にする (元に戻す)
.thenComparing(Element::key2)
.reversed()); // 逆順にする
動作確認
public class Sample {
public static void main(String[] args) {
List<Model> model = new ArrayList<>();
model.add(new Model("model1", 1, 2, 2, 1, 1));
model.add(new Model("model2", 1, 2, 2, 2, 1));
model.add(new Model("model3", 1, 2, 2, 2, 2));
model.add(new Model("model4", 1, 2, 1, 1, 1));
model.add(new Model("model5", 1, 1, 1, 1, 1));
model.add(new Model("model6", 2, 1, 1, 1, 1));
model.stream()
// key1 の降順 > key2 の昇順 > key3 の昇順 > key4 の降順 > key5 の降順
.sorted(Comparator.comparing(Model::getKey1)
.reversed()
.thenComparing(Model::getKey2)
.thenComparing(Model::getKey3)
.reversed()
.thenComparing(Model::getKey4)
.thenComparing(Model::getKey5)
.reversed())
.forEach(System.out::println);
}
}
@Data
@AllArgsConstructor
public class Model {
private String name;
private int key1;
private int key2;
private int key3;
private int key4;
private int key5;
}
実行結果
Model(name=model6, key1=2, key2=1, key3=1, key4=1, key5=1)
Model(name=model5, key1=1, key2=1, key3=1, key4=1, key5=1)
Model(name=model4, key1=1, key2=2, key3=1, key4=1, key5=1)
Model(name=model3, key1=1, key2=2, key3=2, key4=2, key5=2)
Model(name=model2, key1=1, key2=2, key3=2, key4=2, key5=1)
Model(name=model1, key1=1, key2=2, key3=2, key4=1, key5=1)
あとがき
よくよく考えたらメソッドチェーンで繋いでいるんだから当然のように思います。
きちんと調べずにふわっとした理解のままでいるとよくないということを再認識して反省する良い機会でした。
追記:thenComparing() に渡す際に逆順の Comparator を指定すればよい
コメントにて thenComparing() に逆順の Comparator を渡した方が読みやすいというアドバイスをいただきました。
ありがとうございます。
model.stream()
// key1 の降順 > key2 の昇順 > key3 の昇順 > key4 の降順 > key5 の降順
.sorted(
comparing(Model::getKey1).reversed()
.thenComparing(Model::getKey2)
.thenComparing(Model::getKey3)
.thenComparing(comparing(Model::getKey4).reversed())
.thenComparing(comparing(Model::getKey5).reversed())
)
.forEach(System.out::println);
.thenComparing(Model::getKey5).reversed()
と
.thenComparing(comparing(Model::getKey5).reversed())
は動作が異なることを注意点として覚えておかなければならないですね。
(知らなければ私のように「上の書き方で良くない?」となってバグを生むことでしょう。。)