Reputation: 33819
Is there a standard operation in Kotlin stdlib which would allow to iterate over a zip of 3 (or more) lists?
Effectively it should do:
list1.zip(list2).zip(list3) { (a, b), c -> listOf(a, b, c)}
Upvotes: 20
Views: 8615
Reputation: 9567
In complementary to @zsmb13 answer, if you want to zip exactly three lists, you could use the native Triple tuple to literally do what OP suggested:
list1.zip(list2).zip(list3) { (a, b), c -> Triple(a, b, c)}
By declaring it as an extension function, you can make your code feel even more native like:
val x : List<Pair<Int, String>> = listOf(2) zip listOf("a")
val xx : List<Triple<Int, String, Double>> = listOf(2) zip listOf("a") zip listOf(3.0)
public infix fun <A, B, C> Iterable<Pair<A, B>>.zip(other: Iterable<C>) =
zip(other) { (a, b), c -> Triple(a, b, c) }
Upvotes: 1
Reputation: 89608
Here are functions in the style of the standard library that do this. I'm not saying these are particularly optimized, but I think they're at least easy to understand.
/**
* Returns a list of lists, each built from elements of all lists with the same indexes.
* Output has length of shortest input list.
*/
public inline fun <T> zip(vararg lists: List<T>): List<List<T>> {
return zip(*lists, transform = { it })
}
/**
* Returns a list of values built from elements of all lists with same indexes using provided [transform].
* Output has length of shortest input list.
*/
public inline fun <T, V> zip(vararg lists: List<T>, transform: (List<T>) -> V): List<V> {
val minSize = lists.map(List<T>::size).min() ?: return emptyList()
val list = ArrayList<V>(minSize)
val iterators = lists.map { it.iterator() }
var i = 0
while (i < minSize) {
list.add(transform(iterators.map { it.next() }))
i++
}
return list
}
Usage:
val list1 = listOf(1, 2, 3, 4)
val list2 = listOf(5, 6)
val list3 = listOf(7, 8, 9)
println(zip(list1, list2, list3)) // [[1, 5, 7], [2, 6, 8]]
Upvotes: 23