Is there a simple way to divide list of Double
into two lists of pairs in Kotlin?
In such way:
[x1, y1, x2, y2, x3, y3] => [(x1, x2), (x2, x3), (x3, x1)], [(y1, y2), (y2, y3), (y3, y1)]
I tried to use filterIndexed
and zipWithNext
val x = filterIndexed { index, _ -> index % 2 == 0 }.zipWithNext()
val y = filterIndexed { index, _ -> index % 2 == 1 }.zipWithNext()
But the result is:
[x1, y1, x2, y2, x3, y3] => [(x1, x2), (x2, x3)], [(y1, y2), (y2, y3)]
CodePudding user response:
If I understand correctly, the problem with the zipWithNext
that you are using is that it doesn't "wrap around", i.e. output the final (x3, x1) or (y3, y1) pair, containing the last and first elements of the list.
You can fix this by simply declaring your own version of zipWithNext
that does do this.
You can either do something like this:
fun <T> Iterable<T>.zipWithNextAndWrapAround(): List<Pair<T, T>> {
val zippedWithNext = zipWithNext()
if (zippedWithNext.isEmpty()) return zippedWithNext
return zippedWithNext (zippedWithNext.last().second to zippedWithNext.first().first)
}
Or copy and paste over the original source code of zipWithNext
and slightly modify it:
fun <T> Iterable<T>.zipWithNextAndWrapAround(): List<Pair<T, T>> {
val iterator = iterator()
if (!iterator.hasNext()) return emptyList()
val result = mutableListOf<Pair<T, T>>()
var current = iterator.next()
// remember what the first element was
val first = current
while (iterator.hasNext()) {
val next = iterator.next()
result.add(current to next)
current = next
}
// at last, add this pair
result.add(current to first)
return result
}
Usage:
val x = list.filterIndexed { index, _ -> index % 2 == 0 }.zipWithNextAndWrapAround()
val y = list.filterIndexed { index, _ -> index % 2 == 1 }.zipWithNextAndWrapAround()
Note that this is looping through the list twice. You can avoid that by writing your own version of partition
called partitionIndexed
.
The code could be something like:
inline fun <T> Iterable<T>.partitionIndexed(predicate: (Int, T) -> Boolean): Pair<List<T>, List<T>> {
val first = ArrayList<T>()
val second = ArrayList<T>()
forEachIndexed { index, element ->
if (predicate(index, element)) {
first.add(element)
} else {
second.add(element)
}
}
return Pair(first, second)
}
// usage:
val (x, y) = list.partitionIndexed { index, _ ->
index % 2 == 0
}.let { (a, b) ->
a.zipWithNextAndWrapAround() to b.zipWithNextAndWrapAround()
}
CodePudding user response:
You could do something like this:
val lst = listOf(1, 2, 3, 4, 5, 6, 7, 8)
val intermediate = lst.chunked(2).map { it[0] to it[1] }.let { it it[0] }
val x = intermediate.map { it.first }.zipWithNext()
val y = intermediate.map { it.second }.zipWithNext()
println(x) //[(1, 3), (3, 5), (5, 7), (7, 1)]
println(y) //[(2, 4), (4, 6), (6, 8), (8, 2)]
CodePudding user response:
Yes, you can divide a list of doubles into two lists of pairs in Kotlin.
val lst = listOf(x1, y1, x2, y2, x3, y3)
val list1 = lst.chunked(2).map { it[0] to it[1] }
val list2 = lst.drop(2).chunked(2).map { it[0] to it[1] } listOf(lst[0] to lst[2])
The chunked method is used to divide the original list lst into pairs of two elements each. The map function is used to create a new list of pairs from each chunked pair. The second list is created by using the drop method to skip the first two elements of lst and repeating the process.
This will result in two lists of pairs, list1 and list2.
CodePudding user response:
val input = listOf("x1", "y1", "x2", "y2", "x3", "y3")
val result = list
.withIndex()
.groupBy { it.index % 2 }
.map { entry -> entry.value.map { it.value } }
.map { (it it[0]).zipWithNext() }
println(result)
Output:
[[(x1, x2), (x2, x3), (x3, x1)], [(y1, y2), (y2, y3), (y3, y1)]]