38

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
  • 2,895
  • 5
  • 22
  • 34
  • 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

5 Answers5

74

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,712
  • 2
  • 13
  • 17
35

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
  • 36,699
  • 6
  • 110
  • 108
  • 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
29

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
  • 11,381
  • 5
  • 51
  • 69
7

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,062
  • 2
  • 16
  • 29
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,858
  • 4
  • 20
  • 33