Edit Page

コレクションをフィルタ処理する

フィルタ処理はコレクションの処理のうちもっとも良くあるタスクの一つです。 Kotlinでは、フィルタ条件は 述語(predicate) で定義します ー 要素を引数に取りBoolean値を返すラムダ関数の事です: trueは渡された要素が条件にマッチする事を意味し、falseはその反対を意味します。

標準ライブラリは呼び出し一つでコレクションをフィルタ処理する拡張関数をいろいろ用意しています。 これらの関数は元のコレクションは変更しません。つまり、これらの関数はミュータブルと読み取り専用のどちらにも使う事が出来ます。 フィルタ処理した結果に何か操作をしたければ、結果を変数に格納するかフィルタ処理のあとにさらに関数をチェインするかする必要があります。

述語でフィルタ

基本的なフィルタ処理関数はfilter()です。 述語とともに呼ばれると、filter()は述語にマッチした要素だけを返します。 ListSetに対しては結果のコレクションはListになり、Mapの場合は結果もMapになります。

fun main() { //sampleStart val numbers = listOf("one", "two", "three", "four") val longerThan3 = numbers.filter { it.length > 3 } println(longerThan3) val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11) val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10} println(filteredMap) //sampleEnd }

filter()の述語は要素の値だけをチェックします。 もしフィルタ処理で要素の位置も使いたければ、filterIndexed()を使いましょう。 この関数は述語として2つの引数を取る関数を取ります。その2つの引数とはインデックスと要素の値です。

コレクションを否定の条件でフィルタ処理したければ、filterNot()を使いましょう。 これは述語がfalseを返した要素のリストを返します。

fun main() { //sampleStart val numbers = listOf("one", "two", "three", "four") val filteredIdx = numbers.filterIndexed { index, s -> (index != 0) && (s.length < 5) } val filteredNot = numbers.filterNot { it.length <= 3 } println(filteredIdx) println(filteredNot) //sampleEnd }

型を与える事でコレクション内の要素をその型に属するものだけに絞る関数もあります:

  • 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()があります。 これは、述語にマッチする要素を集めたコレクションを作ると同時に、マッチしなかった要素を別のリストに作ります。 つまり、戻りの値としてListPairが返ってくる訳です:最初のリストは述語にマッチした方の要素が含まれていて、 2つ目のリストはそれ以外の要素がすべて入ります。

fun main() { //sampleStart val numbers = listOf("one", "two", "three", "four") val (match, rest) = numbers.partition { it.length > 3 } println(match) println(rest) //sampleEnd }

述語のテスト

最後に、コレクションの要素たちに単に述語をテストしていく関数というのがあります:

  • any() は少なくとも1つ述語にマッチしたら true を返す。
  • none() 述語に一つもマッチしなければ true を返す。
  • all() 述語が全ての要素にマッチしたら true を返す。 空のコレクションに述語を渡すと、all()true を返す事に注意しましょう。そのような振る舞いは論理学では vacuous truth と呼ばれています。
fun main() { //sampleStart val numbers = listOf("one", "two", "three", "four") println(numbers.any { it.endsWith("e") }) println(numbers.none { it.endsWith("a") }) println(numbers.all { it.endsWith("e") }) println(emptyList<Int>().all { it > 5 }) // vacuous truth //sampleEnd }

any()none() は述語無しで使う事も出来ます:この場合はコレクションが空かどうかを単にチェックします。 any() は要素があれば true を返し、そうでなければ false を返す。none() はその反対を行います。

fun main() { //sampleStart val numbers = listOf("one", "two", "three", "four") val empty = emptyList<String>() println(numbers.any()) println(empty.any()) println(numbers.none()) println(empty.none()) //sampleEnd }