2019年2月9日土曜日

【Java】配列やコレクションのソートいろいろ

Java配列をソートするコードを書く

Java配列をソートするコードを書く

いざJavaでコードを書かなければならないという時、配列のソートを思い出すのに苦労することが多いので、備忘も兼ねて、ここにアウトプットしてしまいます。
検討項目
  • プリミティブ型な値を一つだけ持つ配列をソートする
    • ArrayListに変換した後、SortやparallelSortを使う
  • 複数のフィールドを持つ要素の単一のフィールドをソートキーにしてソートする
    • SortやparallelSortを使う。Comparableを継承したフィールド定義クラスを作ったり、Comparatorクラスを実装した比較用クラスを作ったりする。lambdaも使える。
  • 複数のフィールドを持つ要素について、複数のフィールドを優先度付きソートキーにしてソートする
    • 上記同

プリミティブ型な値を一つしか持たない配列をソートする

arraysのソートを活用する

import java.util.Arrays;

class Main {
  public static void main(String[] args) {
    int score[] = { 4, 2, 0, 3, 1 };
    Arrays.sort(score);
    for (int item : score) {
      System.out.print(item + " ");
    }
  }
}
実行結果
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
0 1 2 3 4

複数のフィールドを持つ要素の単一のフィールドをソートキーにしてソートする

SortやparallelSortを使う。フィールドを持つComparableを継承したクラスも作る。

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

class Player implements Comparable {
    private int ranking;
    private String name;
    private int age;

    public Player(int ranking, String name, int age) {
        this.ranking = ranking;
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Player o) {
        return (this.getRanking() - o.getRanking());
    }
    public int getRanking() {
        return ranking;
    }
    @Override
    public String toString() {
        return ranking + " " + name;
    }
}

public class Main {
  public static void main(String[] args) {
    List footballTeam = new ArrayList();

    footballTeam.add(new Player(23, "たかし", 24));
    footballTeam.add(new Player(16, "ひろし", 20));
    footballTeam.add(new Player(18, "けんた", 22));

    System.out.println("Before Sorting : " + footballTeam);
    Collections.sort(footballTeam);
    System.out.println("After Sorting : " + footballTeam);
  }
}
別解。既存かつ変更できないクラスに対し、Comparatorを使って、ソートする。(Java8以降)

import java.util.*;

class Player {
    private int ranking;
    private String name;
    private int age;
    public Player(int ranking, String name, int age) {
        this.ranking = ranking;
        this.name = name;
        this.age = age;
    }
    public int getRanking() {
        return ranking;
    }
    @Override
    public String toString() {
        return ranking + " " + name;
    }
}

class PlayerRankingComparator implements Comparator<Player> {
    public int compare(Player firstPlayer, Player secondPlayer) {
        return (firstPlayer.getRanking() - secondPlayer.getRanking());
    }
}

public class Main {
  public static void main(String[] args) {
    PlayerRankingComparator playerComparator = new PlayerRankingComparator();
    List footballTeam = new ArrayList<Player>();

    footballTeam.add(new Player(23, "たかし", 24));
    footballTeam.add(new Player(16, "ひろし", 20));
    footballTeam.add(new Player(16, "けんた", 22));

    System.out.println("Before Sorting : " + footballTeam);
    Collections.sort(footballTeam, playerComparator);
    System.out.println("After Sorting : " + footballTeam);
  }
}
ComparatorをLambdaにしてやれば、comparator継承クラスも必要なくなる。

import java.util.*;

class Player  {
    private int ranking;
    private String name;
    private int age;

    public Player(int ranking, String name, int age) {
        this.ranking = ranking;
        this.name = name;
        this.age = age;
    }

    public int getRanking() {
        return ranking;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return age + " " + name;
    }
}

public class Main {
  public static void main(String[] args) {
    Comparator<Player> byAge = (Player player1, Player player2) -> 
           player1.getAge() - player2.getAge();
    //Comparator byAge = Comparator.comparingInt(Player::getAge); こちらでも可
    List footballTeam = new ArrayList<Player>();

    footballTeam.add(new Player(23, "たかし", 24));
    footballTeam.add(new Player(16, "ひろし", 20));
    footballTeam.add(new Player(18, "けんた", 22));

    System.out.println("Before Sorting : " + footballTeam);
    Collections.sort(footballTeam, byAge);
    System.out.println("After Sorting : " + footballTeam);
  }
}

複数のフィールドを持つ要素について、複数のフィールドを優先度付きソートキーにしてソートする

import java.util.*;

class Player implements Comparable<Player> {
    private int ranking;
    private String name;
    private int age;

    public Player(int ranking, String name, int age) {
        this.ranking = ranking;
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Player o) {
        if (this.getRanking() == o.getRanking()) {
          return (this.getAge() - o.getAge());
        } else {
          return (this.getRanking() - o.getRanking());
        }
    }
    public int getRanking() {
        return ranking;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString() {
        return ranking + " " + age + " " + name;
    }
}

public class Main {
  public static void main(String[] args) {
    List<Player> footballTeam = new ArrayList<Player>();

    footballTeam.add(new Player(23, "たかし", 24));
    footballTeam.add(new Player(16, "ひろし", 22));
    footballTeam.add(new Player(18, "けんた", 20));
    footballTeam.add(new Player(16, "しげき", 18));

    System.out.println("Before Sorting : " + footballTeam);
    Collections.sort(footballTeam);
    System.out.println("After Sorting : " + footballTeam);
  }
}
結果
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
Before Sorting : [23 24 たかし, 16 22 ひろし, 18 20 けんた, 16 18 しげき]
After Sorting : [16 18 しげき, 16 22 ひろし, 18 20 けんた, 23 24 たかし]
Lambdaで記載してみる。
import java.util.*;

class Player  {
    private int ranking;
    private String name;
    private int age;

    public Player(int ranking, String name, int age) {
        this.ranking = ranking;
        this.name = name;
        this.age = age;
    }

    public int getRanking() {
        return ranking;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return ranking + " " + age + " " + name;
    }
}

public class Main {
  public static void main(String[] args) {
    Comparator<Player> byRankAndAge = ( 
     (Player player1, Player player2) -> 
     {
       if (player1.getRanking() == player2.getRanking()) {
         return (player1.getAge() - player2.getAge());
       } else {
         return (player1.getRanking() - player2.getRanking());
       }
     }
    ); 

    List<Player> footballTeam = new ArrayList<Player>();

    footballTeam.add(new Player(23, "たかし", 24));
    footballTeam.add(new Player(16, "ひろし", 22));
    footballTeam.add(new Player(18, "けんた", 20));
    footballTeam.add(new Player(16, "しげき", 18));

    System.out.println("Before Sorting : " + footballTeam);
    Collections.sort(footballTeam, byRankAndAge);
    System.out.println("After Sorting : " + footballTeam);
  }
}


Java学習ならこの本。第3版には、LambdaやStreamなど、Java8から追加されたイディオムもしっかり載っています。オススメ。