Home > database >  Divide list into two list
Divide list into two list

Time:02-04

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)]]
  • Related