コレクションをフィルタ処理する
フィルタ処理はコレクションの処理のうちもっとも良くあるタスクの一つです。
Kotlinでは、フィルタ条件は 述語(predicate) で定義します ー 要素を引数に取りBoolean値を返すラムダ関数の事です:
true
は渡された要素が条件にマッチする事を意味し、false
はその反対を意味します。
標準ライブラリは呼び出し一つでコレクションをフィルタ処理する拡張関数をいろいろ用意しています。 これらの関数は元のコレクションは変更しません。つまり、これらの関数はミュータブルと読み取り専用のどちらにも使う事が出来ます。 フィルタ処理した結果に何か操作をしたければ、結果を変数に格納するかフィルタ処理のあとにさらに関数をチェインするかする必要があります。
述語でフィルタ
基本的なフィルタ処理関数はfilter()
です。
述語とともに呼ばれると、filter()
は述語にマッチした要素だけを返します。
List
とSet
に対しては結果のコレクションはList
になり、Map
の場合は結果もMap
になります。
filter()
の述語は要素の値だけをチェックします。
もしフィルタ処理で要素の位置も使いたければ、filterIndexed()
を使いましょう。
この関数は述語として2つの引数を取る関数を取ります。その2つの引数とはインデックスと要素の値です。
コレクションを否定の条件でフィルタ処理したければ、filterNot()
を使いましょう。
これは述語がfalse
を返した要素のリストを返します。
型を与える事でコレクション内の要素をその型に属するものだけに絞る関数もあります:
-
filterIsInstance()
は与えられた型と同じ型の要素を返します。List<Any>
に対して呼び出す場合、filterIsInstance<T>()
はList<T>
を返します。つまりその要素に対してT
型にある関数を呼び出す事が出来るようになります。fun main() { //sampleStart val numbers = listOf(null, 1, "two", 3.0, "four") println("All String elements in upper case:") numbers.filterIsInstance<String>().forEach { println(it.uppercase()) } //sampleEnd } -
filterNotNull()
はnullでない要素をすべて返す。List<T?>
に対して呼び出すと、filterNotNull()
はList<T: Any>
を返す。かくして要素をnullでないものとして扱う事が出来るようになる。fun main() { //sampleStart val numbers = listOf(null, "one", "two", null) numbers.filterNotNull().forEach { println(it.length) // lengthはnullableなStringには使えない } //sampleEnd }
Partition(分割)
さらに別のフィルタ関数として、partition()
があります。
これは、述語にマッチする要素を集めたコレクションを作ると同時に、マッチしなかった要素を別のリストに作ります。
つまり、戻りの値としてList
のPair
が返ってくる訳です:最初のリストは述語にマッチした方の要素が含まれていて、
2つ目のリストはそれ以外の要素がすべて入ります。
述語のテスト
最後に、コレクションの要素たちに単に述語をテストしていく関数というのがあります:
any()
は少なくとも1つ述語にマッチしたらtrue
を返す。none()
述語に一つもマッチしなければtrue
を返す。all()
述語が全ての要素にマッチしたらtrue
を返す。 空のコレクションに述語を渡すと、all()
はtrue
を返す事に注意しましょう。そのような振る舞いは論理学では vacuous truth と呼ばれています。
any()
と none()
は述語無しで使う事も出来ます:この場合はコレクションが空かどうかを単にチェックします。
any()
は要素があれば true
を返し、そうでなければ false
を返す。none()
はその反対を行います。