並べ替え
要素の順番は、ある種のコレクションには重要な側面です。 例えば、同じ要素を持つ2つのリストでも、要素の順番が異なればこれらのリストは等しいとはみなされません。
Kotlinでは、オブジェクトの順番を定義する方法はいくつかあります。
最初の方法としては、自然(natural)な順番があります。
これはComparable
インターフェースの実装により定義される順番です。
自然な順番はその他の順番が指定されていない場合のソートで使われる順番です。
多くのビルトインの型は比較可能(comparable)です:
- 数値型は伝統的な数値の順番を使います:
1
は0
よりも大きく、-3.4f
は-5f
よりも大きい、などです。 Char
とString
は辞書式順序を使います:b
はa
より大きく、world
はhello
より大きいです。
ユーザー定義型に自然な順番を定義するためには、その型でComparable
インターフェースを実装する必要があります。
これはcompareTo()
関数を実装する事を意味します。
compareTo()
は同じ型の別のオブジェクトを引数に取り、
どちらのオブジェクトが大きいかを示すIntの値を返します:
- 正の値はレシーバオブジェクトの方が大きい事を示します。
- 負の値はレシーバオブジェクトの方が小さい事を示します。
- 0はオブジェクトが等しい事を示します。
以下はバージョンクラスの順番を、メジャーとマイナーのバージョン番号から決める例です。
カスタムな順番は、どんな型のインスタンスでもお好みなようにソートする事を可能にしてくれます。
とりわけ、Comparableでは無いオブジェクトの順番を定義したり、Comparableな型の自然な順番以外の順番を定義したり出来ます。
ある型のカスタムな順番を定義するためには、Comparator
を作ります。
Comparator
はcompare()
関数を持ちます:これは、指定されたクラスの2つのインスタンスを引数に取り、それらの比較結果を数値として返します。
結果の数値は先に述べたcompareTo()
と同様に解釈されます。
lengthComparator
を使えば、辞書順では無く長さで文字列を並べる事が出来ます。
Comparator
を定義するもっと短い方法としては、標準ライブラリのcompareBy()
関数を使う方法があります。
compareBy()
は、インスタンスからComperable
な値を返すラムダ関数を引数に取り、
その生成された値の自然な順番をカスタムな順番とします。
compareBy()
を使えば、上記のlengthComparatorの例は以下のように書く事が出来ます:
Kotlinのコレクションpackageは、自然な順番、カスタムな順番、ランダムな順番などに並べ替える関数を提供しています。 このページでは、読み取り専用のコレクションをソートする関数を説明します。 これらの関数は指定された順番に並べ替えたコレクションを新しく生成して返します。 ミュータブルをインプレイスにソートする関数を知りたければ、 List特有のオペレーションを参照してください。
自然な順番
(訳注:Natural order)
基本となる関数、sorted()
とsortedDescending()
は、
コレクションの要素をその自然の順番で昇順、または降順に並べ替えたコレクションを生成して返します。
これらの関数はComparable
な要素のコレクションに対して使う事が出来ます。
カスタムな順番
カスタムな順番でソートしたり、そもそもComperableで無いオブジェクトをソートしたい場合には、
sortedBy()
と sortedByDescending()
関数があります。
これらは、コレクションの要素をComperable
な値にマップするセレクタ関数を引数に取り、その値の自然な順番でコレクションをソートします。
コレクションのソートに使う為にカスタムな順番を定義するために、独自のComparator
を渡す事も出来ます。
そのためには、sortedWith()
関数を使い、
独自に定義したComparator
をこれに渡します。
この関数を使って文字列を長さでソートする例は以下のようになります:
逆順
コレクションを逆順にしたものを取り出す事も出来ます。
reversed()
関数を使います。
reversed()
は要素のコピーを含む新規のコレクションを返します。
だからあとになって元となるコレクションを変更しても、変更前に取得したreversed()
の結果には影響を与えません。
(訳注:要素のコピーと言っているが、要素はコピーでは無く同じオブジェクトへの参照だと思う。ここではコレクションが新規に作られると言いたいのだと思われる。)
これとは別のリバースの関数、asReversed()
は同じコレクションインスタンスの、
逆順のビューを返すので、元のコレクションが変更されない事が分かっているならreversed()
よりも軽量で望ましい場合があります。
オリジナルのリストがミュータブルなら、オリジナルのコレクションへの変更はリバースのビューにも影響を与えるし、リバースのビューへの変更もオリジナルのコレクションに影響を与えます。 (訳注:説明には書いていないが、MutableListのasReversedはMutableListを返す)
しかしながら、リストのミュータビリティが不明だったり、そもそも元となるコレクションがリストで無い場合などは、reversed()
の方が結果がコピーになって勝手に変わる事が無い事が保証されるので、
より望ましいと言えます。
ランダムな順番
最後に、ランダムな順番の新たなList
を返す関数があります ー shuffled()
です。
この関数は引数無しで呼び出す事も出来ますし、Random
オブジェクトを引数に呼び出す事も出来ます。