42

Is there a simple way to divide list into parts (maybe some lambda) in Kotlin?

For example:

[1, 2, 3, 4, 5, 6] => [[1, 2], [3, 4], [5, 6]]
Letfar
  • 3,253
  • 6
  • 25
  • 35
  • 1
    that's a feature requested for Kotlin 1.1: https://github.com/Kotlin/KEEP/blob/master/proposals/stdlib/window-sliding.md – succcubbus Nov 21 '16 at 09:43
  • Possible duplicate: http://stackoverflow.com/q/34498368/3255152 – mfulton26 Nov 21 '16 at 14:21
  • 3
    If you're looking to partition into _two_ parts, https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/partition.html would do what you want to do. e.g. `list.partition { x -> x < 4 }` – carpeliam Jul 19 '17 at 13:51

6 Answers6

83

Since Kotlin 1.2 you can use Iterable<T>.chunked(size: Int): List<List<T>> function from stdlib (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/chunked.html).

VasyaFromRussia
  • 1,872
  • 2
  • 14
  • 18
37

Given the list: val list = listOf(1, 2, 3, 4, 5, 6) you can use groupBy:

list.groupBy { (it + 1) / 2 }.map { it.value }

Or if your values are not numbers you can first assign an index to them:

list.withIndex()
    .groupBy { it.index / 2 }
    .map { it.value.map { it.value } }

Or if you'd like to save some allocations you can go a bit more manual way with foldIndexed:

list.foldIndexed(ArrayList<ArrayList<Int>>(list.size / 2)) { index, acc, item ->
    if (index % 2 == 0) {
        acc.add(ArrayList(2))
    }
    acc.last().add(item)
    acc
}
miensol
  • 39,733
  • 7
  • 116
  • 112
  • 1
    For [`groupBy`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/group-by.html), "the returned map preserves the entry iteration order of the keys produced from the original collection." As such, your first example can be simplified to `list.groupBy { (it + 1) / 2 }.values`. – mfulton26 Nov 21 '16 at 14:44
  • 1
    Kotlin has [`withIndex`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/with-index.html) which can make your second example a bit more readable as well: `list.withIndex().groupBy { it.index / 2 }.values.map { it.map { it.value } }`. – mfulton26 Nov 21 '16 at 14:45
  • @mfulton26 thanks for the notice, updated the answer accordingly. – miensol Nov 21 '16 at 20:25
31

The better answer is actually the one authored by VasyaFromRussia.

If you use groupBy, you will have to add and index and then post-process extracting the value from an IndexedValue object.

If you use chunked, you simply need to write:

val list = listOf(10, 2, 3, 4, 5, 6)
val chunked = list.chunked(2)
println(chunked)

This prints out:

[[10, 2], [3, 4], [5, 6]]
gil.fernandes
  • 12,978
  • 5
  • 63
  • 76
13

Nice way of dividing list is by the use of function partition. Unlike groupBy it doesn't divide list by keys but rather by predicate which gives out Pair<List, List> as a result.

Here's an example:

val (favorited, rest) = posts.partition { post ->
    post.isFavorited()
}
favoritedList.addAll(favorited)
postsList.addAll(rest)
Ernest Zamelczyk
  • 2,562
  • 2
  • 18
  • 32
2

The API says there is a GroupBy function, which should do what you want.

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/group-by.html

Or use sublist and break it up yourself

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/sub-list.html

EdH
  • 4,918
  • 4
  • 24
  • 34
0

If you want to divide a list into N parts. (and not divide a list into parts of size N) You can still use the chunked answer:

https://stackoverflow.com/a/48400664/413127

Only, first you need to find your chunk size.

val parts = 2
val list = listOf(10, 2, 3, 4, 5, 6)
val remainder = list.size % 2 // 1 or 0
val chunkSize = (list.size / parts) + remainder
val chunked = list.chunked(chunkSize)
println(chunked)

This prints out

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

or when

val parts = 3

This prints out

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

Interesting answer in Python here: Splitting a list into N parts of approximately equal length

Blundell
  • 75,855
  • 30
  • 208
  • 233