Edited at

Kotlinのリスト操作関数まとめ(1.3.41版)

4年前に書いたこのエントリの最新版です。(2019/7現在)

Kotlinのリスト操作関数まとめ みんからきりまで

最近競プロを始めたら色々とニッチな関数を探すようになった。


以下本文

Kotlinのリスト操作関数、便利なんだけど関数型言語の知見が無い為いつも欲しい機能を探すのに時間を奪われる。

なので適当に調べて備忘メモ。

Kotlin独自ってものはあんまりない気がするので他の言語やRxなどでもだいたい同じっぽい。


変換系


map

・リストの中身を1つずつ処理して別のリストに変換する

listOf(1, 2, 3).map { num -> "num:" + num }

1, 2, 3



["num:1", "num:2", "num:3"]


mapIndexed

・index付きのmap

listOf(1, 2, 3).mapIndexed { i, num -> "i$i=$num" }

[1, 2, 3]



["i0=1", "i1=2", "i2=3"]


mapNotNull

・関数の返り値がnullだったら変換後のリストに含めない。

他のxxxNotNull系関数も同じ。

listOf(1, null, 3).mapNotNull { num -> if (num == null) null else "num:$num" }

[1, null, 3]



["num:1", "num:3"]


flatMap

・2次元リストをフラット(1次元)リストに変換する

※mapのリストを分解する版

arrayListOf(arrayListOf(1, 2, 3), arrayListOf(4, 5, 6)).flatMap { num -> num }

[[1, 2, 3], [4, 5, 6]]



[1, 2, 3, 4, 5, 6]


associate

高階関数で返したPairをMapにして返す。

もしKeyが同じものがあれば最後のPairのみが返される

listOf(1, 1, 2, 2, 3).associate { num -> "num$num * 2" to num * 2 }

[1, 1, 2, 2, 3]



{num1 * 2=2, num2 * 2=4, num3 * 2=6}


associateWith

associateでは高階関数でPairを返すが、associateWithではValueのみを返し、Keyにはリストの値そのものが使用される

listOf(1, 1, 2, 2, 3).associateWith { num -> num * 2 }

[1, 1, 2, 2, 3]



{1=2, 2=4, 3=6}


associateBy

associateWithのKeyとValueが逆になる


抽出系


filter

・trueを返した要素だけ抽出する

listOf(1, 2, 3).filter { num -> num != 2 }

1, 2, 3



1, 3


filterNot

・falseを返した要素だけ抽出する


groupBy

返した値をKeyにグループ分けされたリストのMapを返す

listOf(1, 2, 3, 4, 5).groupBy {num -> if (num % 2 == 0) "偶数" else "奇数" }

[1, 2, 3, 4, 5]



{奇数=[1, 3, 5], 偶数=[2, 4]}


chunked

値を指定したsizeごとに区切って二次元リストにする。

listOf(1, 2, 3, 4, 5).chunked(2)

[1, 2, 3, 4, 5]



[[1, 2], [3, 4], [5]]


partition

返したBooleanの値によってリストを分割したPairを返す。

listOf(1, 2, 3, 4, 5).partition {num -> num % 2 == 0 }

[1, 2, 3, 4, 5]



([2, 4], [1, 3, 5])


take

・指定した数だけ要素を抽出する

listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).take(4)

1, 2, 3, 4, 5, 6, 7, 8, 9, 10



1, 2, 3, 4


takeLast

・後ろから数えて指定した数だけ要素を抽出する

listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).takeLast(4)

1, 2, 3, 4, 5, 6, 7, 8, 9, 10



6, 7, 8, 9, 10


drop

・先頭から指定した数だけ要素を捨てる

listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).drop(4)

1, 2, 3, 4, 5, 6, 7, 8, 9, 10



5, 6, 7, 8, 9, 10


single

・trueを返した要素が1つならそのまま返し、空もしくは複数ならExceptionを投げる

listOf(1, 2, 3, 1).single { num -. num == 1 }

1, 2, 3



1

1, 1, 2



IllegalArgumentException: Collection contains more than one matching element.


singleOrNull

・trueを返した要素が1つならそのまま返し、空もしくは複数ならnullを返す

listOf(1, 2, 3).singleOrNull { num -. num == 1 }

1, 2, 3



1

1, 1, 2



null


max

・最大値を返す

listOf(1, 2, 3).max()

1, 2, 3



3


min

・最小値を返す

listOf(1, 2, 3).max()

1, 2, 3



1


maxBy, minBy

・返した要素を使用して最大値, 最小値を返す

listOf("a", "aaa", "aa").maxBy { s -> s.length() }

"a", "aaa", "aa"



"aaa"


distinct

・重複を削除する

listOf(1, 2, 1, 2).distinct()

1, 2, 1, 2



1, 2


distinctBy

・返した要素で重複を削除する

listOf("abc", "de", "fgh", "i", "jk").distinctBy { s -> s.length() }

"abc", "de", "fgh", "i", "jk"



"abc", "de", "i"


first

・最初の要素を返す


last

・最後の要素を返す


slice

指定したindexの範囲を抽出したリストを返す

subListよりも直感的

listOf(1, 2, 3, 4, 5).slice(3..4)

[1, 2, 3, 4, 5]



[4, 5]


random

・ランダムな要素を返す


ソート系


sorted

・並び替える

listOf(2, 1, 3).sorted()

2, 1, 3



1, 2, 3


sortedBy

・返した要素を使用して並び替える

listOf("a", "aaa", "aa").sortBy { s -> s.length() }

"a", "aaa", "aa"



"a", "aa", "aaa"


sortedDescendingBy

・返した要素を使用して降順に並び替える


reversed

・要素を逆順にする

・並び替える

listOf(1, 2, 3).reversed()

1, 2, 3



3, 2, 1


判定系


equals

2つのリストの要素が一致していればtrue

== 演算子で代用できる


all

・全ての要素が条件に一致すればtrue

listOf(1, 2, 3, 4).all { num -> num < 10 }

true


any

・どれかの要素が条件に一致すればtrue

listOf(1, 20, 300, 4000).any { num -> num < 10 }

true


isEmpty, isNotEmpty

・リストが空ならtrue、Notは逆


none

・条件に一致する要素が無ければtrue

listOf(1, 2, 3, 4).none { num -> num > 10 }

true


計算系


sum

・合計値を返す


sumBy

・関数で返した要素を使用して合計値を返す

listOf("a", "b", "c").sumBy { it.length }

["a", "b", "c"]



3


average

・平均値を返す


reduce, reduceRight

・要素に対して再帰的に関数を適用し、一つの値にまとめる

・reduceは前から、reduceRightは後ろから要素を取り出す

listOf("a", "b", "c", "d", "e", "f", "g").reduce { s1, s2 -> s1 + s2 }

"a", "b", "c", "d", "e", "f", "g"



"abcdefg"

※この例では

"a" + "b" →"ab" + "c" →"abc" + "d" のように順番に要素を足している


fold, foldRight

・初期値を与えられるreduce


count

・関数の条件に一致する要素の数を返す

listOf("a", "b", "c", "d", "e", "f", "g").fold("first:") { s1, s2 -> s1 + s2 }

"a", "b", "c", "d", "e", "f", "g"



"first:abcdefg"


合成系


plus

・2つのリストを結合する

+ 演算子で代用可能

listOf(1, 2, 3).plus(listOf(4, 5))

1, 2, 3

4, 5



1, 2, 3, 4, 5


zip

・2つのリストの要素をペアにして返す。あまりは捨てられる

listOf(1, 2, 3, 4).zip(listOf("a", "b", "c"))

1, 2, 3, 4

"a", "b", "c"



[[1, "a"], [2, "b"], [3, "c"]]


merge

・2つのリストの要素に関数を適用して合成する。あまりは捨てられる

listOf("a", "b", "c", "d").merge(listOf("1", "2", "3")) { s1, s2 -> s1 + ":" + s2 }

"a", "b", "c", "d"

"1", "2", "3"



"a:1", "b:2", "c:3"


mapTo

呼び出したリストに対して第二引数の関数を適用する。

その後、第一引数に渡されたリストと合成する。

この関数は破壊的関数で、引数に渡したリストも書き換わる。

以下のような結果になる。

なかなかに用途がよくわからない。

val list1 = mutableListOf(1,2,3)

val list2 = listOf(4, 5, 6).mapTo(list1) { num -> num * 2}

list1:[1,2,3]

list2:[4, 5, 6]



list1:[1, 2, 3, 8, 10, 12]

list2:[1, 2, 3, 8, 10, 12]


処理系


forEach

・要素に対して順番に関数を実行する


forEachIndexed

・要素に対して順番に関数を実行する。要素と一緒にindexも受け取れる