こんにちは。
開発部第1グループ、Android担当の沓名です。
Androidの開発において、言語としてKotlinを選択することは今やスタンダードになっています。
JavaからKotlinに変わり、色々と快適になったと思える要素はありますが、その中でも、各種Collection関数は本当に便利だと個人的に感じています。
その名の通り、リストやコレクションの各要素に対する操作を容易に行うために用意されている関数ですが、とにかく数が豊富で様々なシチュエーションに対応できるようになっています。
今回はそんなCollection関数について紹介できればと思います。
Collection関数の簡単な例
JavaでいうforEach文をイメージしていただけると分かりやすいかと思います。
例えば、以下のようなコードがあるとします。
List<String> list = Arrays.asList("ab", "cde", "fg", "hij"); list.forEach(s -> { if(s.length() == 3) { System.out.println(s) } }); >> 出力結果: cde hij
文字列のリストから3文字の要素のみ出力する、という簡単なコードです。
これをKotlinで置き換えると以下のようになります。
val list = listOf("ab", "cde", "fg", "hij") list.filter { s -> s.count() == 3 }.forEach { println(it) } >> 出力結果: cde hij
極端な例ではありますが、シンプルにすることができました。
この例ではfilterとforEachをリストに対して使用して出力を行っています。
このような関数がKotlinにはたくさん用意されています。
Collection関数の全貌
実際、どのようなCollection関数があるのか。
復習も兼ねて改めて調べてみたので、以下に記載しています。
とても数が多いので、興味のある方のみ読んでみてください。
Kotlinのバージョンアップで追加された関数は意外と見落としがちなので、赤字にしてあります。
※順番はKotlinの_Collections.ktに記載されている順なので結構めちゃくちゃです。
1. elementAt
elementAt, elementAtOrElse, elementAtOrNull
2. find
find, findLast
3. first
first, firstNotNullOf(Since: Kotlin 1.5), firstNotNullOfOrNull(Since: Kotlin 1.5),firstOrNull
4. getOrElse
5. getOrNull
6. indexOf
indexOf, indexOfFirst, indexOfLast
7. last
last, lastIndexOf, lastOrNull
8. random
random(Since: Kotlin 1.3), randomOrNull(Since: Kotlin 1.4)
9. single
single, singleOrNull
10. drop
drop, dropLast, dropLastWhile, dropWhile
11. filter
filter, filterIndexed, filterIndexedTo, filterIsInstance,
filterIsInstanceTo, filterNot, filterNotNull, filterNotNullTo,
filterTo
12. slice
12. take
take, takeLast, takeLastWhile, takeWhile
13. reverse
reverse, reversed
14. shuffle(Since: Kotlin 1.3)
15. sort
sortBy, sortByDescending, sortDescending,
sorted, sortedBy, sortedByDescending,
sortedDescending, sortedWith
16. to◯◯Array
toBooleanArray, toByteArray, toCharArray,
toDoubleArray, toFloatArray, toIntArray,
toLongArray, toShortArray
17. associate
associate, associateBy, associateByTo, associateTo,
associateWith(Since: Kotlin 1.3), associateWithTo(Since: Kotlin 1.3)
18. to◯◯
toCollection, toHashSet, toList,
toMutableList, toSet, toMutableSet
19. flatMap(Since: Kotlin 1.4)
flatMap, flatMapIndexed, flatMapIndexedTo, flatMapTo
20. groupBy
groupBy, groupByTo, groupingBy(Since: Kotlin 1.1)
21. map
map, mapIndexed, mapIndexedNotNull,
mapIndexedNotNullTo, mapIndexedTo, mapNotNull,
mapNotNullTo, mapTo
22. withIndex
23. distinct
distinct, distinctBy
24. intersect
25. subtract
26. union
27. all
28. any
29. count
30. fold
fold, foldIndexed, foldRight, foldRightIndexed
31. forEach
forEach, forEachIndexed
32. max
Kotlin1.4以降、以下のメソッドはDeplecate
max, maxBy, maxWith
代わりに1.4以降は以下のメソッドの使用が推奨
maxByOrNull(Since: Kotlin 1.4), maxOf(Since: Kotlin 1.4),
maxOfOrNull(Since: Kotlin 1.4), maxOfWith(Since: Kotlin 1.4),
maxOfWithOrNull(Since: Kotlin 1.4), maxOrNull(Since: Kotlin 1.4),
maxWithOrNull(Since: Kotlin 1.4)
33. min
Kotlin1.4以降、以下のメソッドはDeplecate
min, minBy, minWith
代わりに1.4以降は以下のメソッドの使用が推奨
minByOrNull(Since: Kotlin 1.4), minOf(Since: Kotlin 1.4),
minOfOrNull(Since: Kotlin 1.4), minOfWith(Since: Kotlin 1.4),
minOfWithOrNull(Since: Kotlin 1.4), minOrNull(Since: Kotlin 1.4),
minWithOrNull(Since: Kotlin 1.4)
34. none
35. onEach
onEach(Since: Kotlin 1.1), onEachIndexed (Since: Kotlin 1.4)
36. reduce
reduce, reduceIndexed,
reduceIndexedOrNull(Since: Kotlin 1.4), reduceOrNull(Since: Kotlin 1.4),
reduceRight, reduceRightIndexed,
reduceRightIndexedOrNull(Since: Kotlin 1.4), reduceRightOrNull(Since: Kotlin 1.4)
37. runningFold (Since: Kotlin 1.4)
runningFold, runningFoldIndexed
38. runningReduce(Since: Kotlin 1.4)
runningReduce, runningReduceIndexed
39. scan(Since: Kotlin 1.4)
scan, scanIndexed
40. sum
sum, sumOf(Since: Kotlin 1.4)
以下はkotlin1.5からDeprecate
sumBy, sumByDouble
41. requireNoNulls
42. chunked(Since: Kotlin 1.2)
43. minus
minus, minusElement
44. partition
45. plus
plus, plusElement
46. windowed(Since: Kotlin 1.2)
47. zip
zip, zipWithNext(Since: Kotlin 1.2, 1.4)
48. joinTo
joinTo, joinToString
49. as◯◯
asIterable, asSequence
50. average
抜粋
出来る限り全てのCollection関数を調べて記載しましたが、
多すぎるのでよく使うものやあまり使ったことがないけど使えそうなものを抜粋して紹介します。
1. map(transform: (T) -> R): List
こちらはリストの要素の値を操作してから別のリストにして返すメソッドです。
APIの返却値を格納したEntityクラスをModelクラスに変換する時などによく使います。
例:
data class Entity(val key: String, val value: String) data class Model(val key: String, val value: String, keyValue: String) val entityList = listOf(Entity("key1", "value1"), Entity("key2", "value2")) val modelList = entityList.map { entity -> Model(key = entity.key, value = entity.value, keyValue = entity.key + entity.value) } println(modelList) >> 出力結果: [Model(key=key1, value=value1, keyValue=key1value1), Model(key=key2, value=value2, keyValue=key2value2)]
2. filter(predicate: (T) -> Boolean): List
冒頭でも例に上げましたが、こちらはリストの各要素から、指定した条件に当てはまる要素のみを抜き出してリストにして返すメソッドです。
リストから特定の条件の要素のみ抜き出したい時などによく使います。
例:
data class Entity(val key: String, val value: String, val isPrintFlag: Boolean) val entityList = listOf(Entity("key1", "value1", true), Entity("key2", "value2", false), Entity("key3", "value3", true), Entity("key4", "value4", false)) val filteringList = entityList.filter{ it.isPrintFlag } println(filteringList) >> 出力結果: [Entity(key=key1, value=value1, isPrintFlag=true), Entity(key=key3, value=value3, isPrintFlag=true)]
3. sortedBy(crossinline selector: (T) -> R?): List
こちらは条件を指定して昇順に並び替えたリストを返すメソッドです。
リストを特定の要素の順番に並び替えたいときなどによく使用します。
例:
data class Entity(val key: String, val value: String, val sortNum: Int) val entityList = listOf(Entity("key1", "value1", 4), Entity("key2", "value2", 2), Entity("key3", "value3", 3), Entity("key4", "value4", 1)) val sortedList = entityList.sortedBy{ it.sortNum } println(sortedList) >> 出力結果: [Entity(key=key4, value=value4, sortNum=1), Entity(key=key2, value=value2, sortNum=2), Entity(key=key3, value=value3, sortNum=3), Entity(key=key1, value=value1, sortNum=4)]
4. union(other: Iterable): Set
引数で指定したリストの要素と元のリストの要素を集め、重複を削除したSetにして返すメソッドです。
ほぼ使ったことはありませんが、異なる2つのリストの要素からmapなどで特定の要素を抜き出したリストをそれぞれ作り、重複を削除した上で合体させたい時などに使えそうです。
例:
data class Entity(val key: String, val value: String) val entityList1 = listOf(Entity("key1", "北海道"), Entity("key2", "東京"), Entity("key3", "沖縄"), Entity("key4", "アメリカ"), Entity("key5", "カナダ")) val entityList2 = listOf(Entity("key6", "神奈川"), Entity("key7", "長野"), Entity("key8", "アメリカ"), Entity("key9", "東京"), Entity("key10", "大阪")) println(entityList1.map { it.value }.union(entityList2.map { it.value })) >> 出力結果: [北海道, 東京, 沖縄, アメリカ, カナダ, 神奈川, 長野, 大阪]
5. zip(other: Array): List<Pair<T, R>>
こちらは2つのリストからPairのリストを生成するメソッドです。
こちらもあまり使ったことはありませんが、関連がありつつもデータ構造の異なる2つのリストを一纏めにしておきたい時に使えそうです。
例:
data class BasicData(val key: String, val value: String) data class AuthData(val accessToken: String, val refreshToken: String) val basicList = listOf(BasicData("key1", "value1"), BasicData("key2", "value2"), BasicData("key3", "value3")) val authList = listOf(AuthData("accessToken1", "refreshToken1"), AuthData("accessToken2", "refreshToken2"), AuthData("accessToken3", "refreshToken3")) val zipList = basicList.zip(authList) println(zipList) >> 出力結果: [(BasicData(key=key1, value=value1), AuthData(accessToken=accessToken1, refreshToken=refreshToken1)), (BasicData(key=key2, value=value2), AuthData(accessToken=accessToken2, refreshToken=refreshToken2)), (BasicData(key=key3, value=value3), AuthData(accessToken=accessToken3, refreshToken=refreshToken3))]
まとめ
改めて調べてみて分かりましたが、Collection関数は本当に種類が豊富です。
Kotlinのバージョンアップで新機能が追加されることも多いので、要チェックです。
Collection関数を上手く使えば、複雑なListの操作であってもかなりシンプルに書けることがわかります。
「ここの記述、少し冗長だな」と思ったときはCollection関数でシンプルに出来ないか考える癖をつければ、
可読性の高い簡潔なプログラムを作ることに繋がることかと思います。
今回は以上になります。
皆様、良いKotlinライフを…。
参考URL
- Kotlinのコレクションの使い方メモ
https://qiita.com/opengl-8080/items/36351dca891b6d9c9687
- Kotlin 1.2で追加されたコレクションメソッド
https://developer.android.com/about/versions/12/behavior-changes-12?hl=ja