Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

Javaで優先順位をつけて複数のキーでソートする方法

スポンサードリンク



久々にPureなJavaを書きました(*´Д`)

複数のキーでソートする書き方の説明

いろいろ書き方はありますが、
対象のクラスにComparableをimplementsして
compareTo()をオーバーライドすると
ソート順を定義できます。
そのうえで、

-1(左が先)
 0(同じ)
 1(右が先)

の値を返してやればいいのですが、
複数ある時は、
第1条件の判定結果を変数に格納してやり、
それで0の時は第2条件を判定、
さらに0の時は第3条件を判定……
さらに0の時は第4条件を判定……
とすると、第1条件、第2条件、第3条件………の順でソートされます。

ちなみに並び順を変えたいときは定数なり、enumなりでcompareTo()の中を分岐させます。

サンプルコード

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@Data
@AllArgsConstructor
class Student implements Comparable<Student> {
    // 並び順にあまり意味はない…並び替えの名前もテキトー
    public static enum SortMethod {
        GRADE_CLAZZ_ASC,   /* 学年(ASC) > 学級(ASC) > 名前(ASC) > 班長(T>F) */
        GRADE_CLAZZ_DESC,  /* 学年(DSC) > 学級(DESC) > 名前(DESC) > 班長(F>T) */
    }
    @Getter
    @Setter
    private static SortMethod method = SortMethod.GRADE_CLAZZ_ASC;

    private int grade; /* 学年 */
    private String clazz; /* 学級 */
    private String name; /* 名前 */
    private boolean isLeader; /* 班長 */

    @Override
    public int compareTo(Student o) {
        int result = 0;
        if (method == SortMethod.GRADE_CLAZZ_ASC) {
            result = Integer.valueOf(this.grade).compareTo(Integer.valueOf(o.grade));
            if (result == 0) {
                result = this.clazz.compareTo(o.clazz);
            }
            if (result == 0) {
                result = this.name.compareTo(o.clazz);
            }
            if (result == 0) {
                result = Boolean.valueOf(this.isLeader).compareTo(Boolean.valueOf(o.isLeader));
            }
        } else if (method == SortMethod.GRADE_CLAZZ_DESC) {
            result = -Integer.valueOf(this.grade).compareTo(Integer.valueOf(o.grade));
            if (result == 0) {
                result = -this.clazz.compareTo(o.clazz);
            }
            if (result == 0) {
                result = -this.name.compareTo(o.clazz);
            }
            if (result == 0) {
                result = -Boolean.valueOf(this.isLeader).compareTo(Boolean.valueOf(o.isLeader));
            }
        }
        return result;
    }

    @Override
    public String toString() {
        return "学年 [" + this.grade + "] クラス [" + this.clazz + "] 名前 [ "
                + String.format("%1$-20s", this.name)  // 20文字右スペース埋め (こんな便利なメソッドあったんだ)
                + "] " + (isLeader ? "班長" : "");
    }
}

public class SortSample {
    public static void main(String[] args) {
        // テキトーにデータをぶち込む
        List<Student> students = new ArrayList<>(
                Arrays.asList(
                        new Student(6, "A", "Robin Givens", true),
                        new Student(6, "A", "Richard Burgi", false),
                        new Student(2, "A", "Sarah Walker", false),
                        new Student(2, "A", "Jon Casey", false),
                        new Student(2, "B", "Morgan Grimes", false),
                        new Student(1, "A", "Elenor Batorwski", false),
                        new Student(6, "B", "Agatha Christie", true),
                        new Student(5, "A", "Tony Todd", true),
                        new Student(5, "A", "Matthew Bomer", false),
                        new Student(4, "A", "Linda Hamilton", false),
                        new Student(3, "A", "Lauren Cohan", true),
                        new Student(2, "A", "Chales Bartowski", true),
                        new Student(5, "B", "Rachel Bilson", true),
                        new Student(4, "A", "Nicole Richie", false),
                        new Student(1, "B", "Devon Woodcomb", false)
                )
        );
        Student.setMethod(Student.SortMethod.GRADE_CLAZZ_ASC);
        Collections.sort(students);
        for (Student s : students) {
            System.out.println(s);
        }
        System.out.println("------------------------------------------------");
        // Stream APIでソート
        Student.setMethod(Student.SortMethod.GRADE_CLAZZ_DESC);
        students.stream().sorted((e1, e2) -> e1.compareTo(e2)).forEach(System.out::println);
        System.out.println("------------------------------------------------");
    }
}

Lombokを使っていますので、とりあえず、Mavenを書きます。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>SortSample</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

実行結果

学年 [1] クラス [A] 名前 [ Elenor Batorwski    ] 
学年 [1] クラス [B] 名前 [ Devon Woodcomb      ] 
学年 [2] クラス [A] 名前 [ Sarah Walker        ] 
学年 [2] クラス [A] 名前 [ Jon Casey           ] 
学年 [2] クラス [A] 名前 [ Chales Bartowski    ] 班長
学年 [2] クラス [B] 名前 [ Morgan Grimes       ] 
学年 [3] クラス [A] 名前 [ Lauren Cohan        ] 班長
学年 [4] クラス [A] 名前 [ Linda Hamilton      ] 
学年 [4] クラス [A] 名前 [ Nicole Richie       ] 
学年 [5] クラス [A] 名前 [ Tony Todd           ] 班長
学年 [5] クラス [A] 名前 [ Matthew Bomer       ] 
学年 [5] クラス [B] 名前 [ Rachel Bilson       ] 班長
学年 [6] クラス [A] 名前 [ Robin Givens        ] 班長
学年 [6] クラス [A] 名前 [ Richard Burgi       ] 
学年 [6] クラス [B] 名前 [ Agatha Christie     ] 班長
------------------------------------------------
学年 [6] クラス [B] 名前 [ Agatha Christie     ] 班長
学年 [6] クラス [A] 名前 [ Richard Burgi       ] 
学年 [6] クラス [A] 名前 [ Robin Givens        ] 班長
学年 [5] クラス [B] 名前 [ Rachel Bilson       ] 班長
学年 [5] クラス [A] 名前 [ Matthew Bomer       ] 
学年 [5] クラス [A] 名前 [ Tony Todd           ] 班長
学年 [4] クラス [A] 名前 [ Nicole Richie       ] 
学年 [4] クラス [A] 名前 [ Linda Hamilton      ] 
学年 [3] クラス [A] 名前 [ Lauren Cohan        ] 班長
学年 [2] クラス [B] 名前 [ Morgan Grimes       ] 
学年 [2] クラス [A] 名前 [ Chales Bartowski    ] 班長
学年 [2] クラス [A] 名前 [ Jon Casey           ] 
学年 [2] クラス [A] 名前 [ Sarah Walker        ] 
学年 [1] クラス [B] 名前 [ Devon Woodcomb      ] 
学年 [1] クラス [A] 名前 [ Elenor Batorwski    ] 
------------------------------------------------

あとがき

けっこうこういうコード書くはずなのだけど、ぐぐってもほとんど出てこなかったので書きました。
っていうかあれか、たいていDBから取ってくるときに既にソートして取ってるから
そのあと並び替えするなんてことあんまりしないですよね。
本当はStrategyパターンを書きたかったのですが、前書きで終了してしまいました。
次はStrategyパターンを書きます。

とおもったけど、そもそもStream APIでComparator.comparing()/Comparator.thenComparing()を使えばOKです。
blog1.mammb.com