Kotlinのchunkedについて

採用はこちら

Kotlin の chunked は、コレクションや文字列を扱う際によく使われる便利な拡張関数で、「一定サイズごとに分割する」ことを目的としています。

単なる使い方だけでなく、挙動の前提・注意点・他の関数との違いまで理解しておくと、実務でのバグや設計ミスを防げます。

目次

chunked とは何か(概要)

chunkedIterable / Sequence / CharSequence(String) に対して使える拡張関数で、

要素を指定したサイズごとの「塊(chunk)」に分割する

ための関数です。

イメージ

[1, 2, 3, 4, 5, 6, 7]
↓ chunked(3)
[[1, 2, 3], [4, 5, 6], [7]]

最後のチャンクは、指定サイズに満たなくても必ず返される点が重要です。

基本的な使い方(List / Iterable)

val list = listOf(1, 2, 3, 4, 5, 6, 7)
val result = list.chunked(3)
println(result)

出力

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

戻り値の型

List<List<T>>
  • 元のコレクション型に関係なく、結果は List<List<T>>
  • 元の要素順は 保持される

String(文字列)での chunked

StringCharSequence を実装しているため、そのまま chunked を使用できます。

val text = "KOTLIN"
println(text.chunked(2))
[KO, TL, IN]

日本語文字についての注意点

val text = "こんにちは"
println(text.chunked(2))
[こん, にち, は]

Kotlin の String.chunkedUTF-16 の Char(コード単位) で分割します。

そのため、ひらがな・漢字など一般的な日本語文字は問題になりにくい一方で、

  • 絵文字(サロゲートペア)
  • 結合文字(見た目1文字だが内部的に複数 Char)

を含む場合は、見た目上の「1文字」単位で分割される保証はありません

chunked は「文字数」ではなく Char 数で区切る関数である点は、実務では必ず意識しておく必要があります。

transform 付き chunked(非常に重要)

chunked には チャンクごとに変換処理を行うオーバーロードがあります。

chunked(size: Int, transform: (List<T>) -> R): List<R>

例:チャンク単位で合計を計算

val numbers = listOf(1, 2, 3, 4, 5, 6)

val sums = numbers.chunked(2) { chunk ->
    chunk.sum()
}

println(sums)
[3, 7, 11]

特徴

  • 結果は List<R> になり、List<List<T>> を最終結果として保持しない
  • 各チャンク自体は List<T> として生成されるが、
    map + chunked を分けて書くより意図が明確
  • 可読性・保守性・パフォーマンスのバランスが良い

CharSequence.chunked の transform では、ラムダ引数は CharSequence になります。

chunkedwindowed の違い(重要)

項目chunkedwindowed
分割方式固定サイズの非重複スライド式
重複なしあり
主な用途バッチ処理連続比較・移動処理

windowed の例

val list = listOf(1, 2, 3, 4)
println(list.windowed(2))
[[1, 2], [2, 3], [3, 4]]

chunked の場合

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

補足すると、chunked(size) は概念的にはwindowed(size, step = size, partialWindows = true) の簡易版です。

Sequencechunked(遅延評価)

val seq = generateSequence(1) { it + 1 }

val result = seq
    .chunked(3)
    .take(3)
    .toList()

println(result)
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
  • Sequence.chunked遅延評価
  • 無限シーケンスでも take などの終端操作で安全に制御可能
  • 大量データ処理やストリーム処理と相性が良い

実務でよくあるユースケース

API のバッチ送信

userIds.chunked(100).forEach { batch ->
    sendApi(batch)
}

UI レイアウト用の分割

items.chunked(3).forEach { row ->
    // 3列表示
}

固定長データ・CSV処理

val record = "ABCDE12345"
val fields = record.chunked(5)

注意点・落とし穴

サイズは必ず 1 以上

list.chunked(0) // IllegalArgumentException

最後のチャンクはサイズ保証されない

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

Set での使用について

Set順序を前提としないコレクション型です。
setOf() は多くの場合挿入順を保持しますが、型としては保証されていません

  • 順序が重要 → List を使う
  • 明示したい → toList() で変換する

map + chunked vs chunked(transform)

分離した書き方

list.chunked(3).map { it.sum() }

推奨

list.chunked(3) { it.sum() }
  • 中間処理が減る
  • 処理意図が明確
  • 実務ではこちらが読みやすい

まとめ

  • chunked一定サイズごとの分割
  • 最後のチャンクは小さくなる可能性あり
  • transform 付きが実務では特に有用
  • 文字列では Char(UTF-16)単位で分割される
  • 大量データでは Sequence と組み合わせると安全

以上、Kotlinのchunkedについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次