Kotlinの Iterable#chunked
が便利だな~と思っていた矢先、JavaでListを複数のリストに分割する機会があった。
検索すると独自の実装方法が上位に出てくるが、たぶんCommons CollectionsかGuavaに用意されてるだろうと思ったら、両方にあったのでメモ。
Kotlinのchunked
Iterable
または Sequence
の関数。引数として数値を取り、その要素数ごとに分割した List
を返す。
- Iterable
#chunked の戻り値はList<List<T>>
- Sequence
#chunked の戻り値はSequence<List<T>>
val list = (0..5).toList() // 0~5までの6要素 // 引数で指定した要素数のサブリストのリストが返る assert(list.chunked(3) == listOf(listOf(0, 1, 2), listOf(3, 4, 5))) // 割り切れない場合、末尾のリストの要素数が少なくなる assert(list.chunked(4) == listOf(listOf(0, 1, 2, 3), listOf(4, 5))) // 要素数以上の値を指定した場合、先頭のリストにすべての要素が含まれる assert(list.chunked(6) == listOf(listOf(0, 1, 2, 3, 4, 5))) assert(list.chunked(7) == listOf(listOf(0, 1, 2, 3, 4, 5)))
第2引数で変換関数を取ることもできるが割愛。
内部的には、Iterable#windowedやSequence#windowedの引数 size
と step
に第1引数を、 partialWindows
に true
を指定している模様。
val list = (0..5).toList() // windowedのsizeは分割する要素数 // stepは次のリスト生成時の先頭要素の移動数 // partialWindowsはsize未満のリストを保持するか assert(list.chunked(3) == list.windowed(size = 3, step = 3, partialWindows = true)) assert(list.chunked(5) == list.windowed(size = 5, step = 5, partialWindows = true)) assert(list.chunked(6) == list.windowed(size = 6, step = 6, partialWindows = true)) assert(list.chunked(7) == list.windowed(size = 7, step = 7, partialWindows = true))
Javaでの実装
これをJavaでやりたい場合、Guava v19.0以降、またはCommons Collections v4以降を使用する。
Guava
Guava v19.0で追加された、Lists#partitionで、第1引数のListを第2引数の要素数で分割できる。
分割された内部リストはList#subListによるもののため、第1引数で渡したリストへの変更や、内部リストへの変更がそれぞれに反映されることに注意。
Commons Collections4
Commons Collections v4.0で追加された、ListUtils#partitionを使用可能。
Adapted from http://code.google.com/p/guava-libraries/
とあるように、Guavaの Lists#partition
と同じように使える。 List#subList
を使っていることなども同じ。
振り返り
Commons Collectionsはv4以上でないと使えないのと、Spring Bootなどのフレームワークを使って実装している場合、依存関係で自然とGuavaが使えたりするので、Guavaのほうが利用のためのハードルは低そう。
独自で実装とかすると、エラー出たときとか面倒なので、極力ライブラリを使いたいものです。