Add Sequence.coalesce()
This commit is contained in:
parent
51d14216e9
commit
a8137c6ee4
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
gradle*
|
gradle*
|
||||||
.gradle/
|
.gradle/
|
||||||
|
build/
|
||||||
|
out/
|
||||||
|
47
src/main/kotlin/moe/kageru/sekwences/Sekwences.kt
Normal file
47
src/main/kotlin/moe/kageru/sekwences/Sekwences.kt
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package moe.kageru.sekwences
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a sequences that optionally merges adjacent elements.
|
||||||
|
* Heavily inspired by Itertools.coalesce() from the Rust crate.
|
||||||
|
*
|
||||||
|
* https://docs.rs/itertools/0.8.0/itertools/trait.Itertools.html#method.coalesce
|
||||||
|
*/
|
||||||
|
fun <T> Sequence<T>.coalesce(merger: (T, T) -> T?): Sequence<T> {
|
||||||
|
return if (this.iterator().hasNext()) {
|
||||||
|
CoalescingSequence(this, merger)
|
||||||
|
} else {
|
||||||
|
emptySequence()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CoalescingSequence<T>(private val source: Sequence<T>, private inline val merger: (T, T) -> T?) : Sequence<T> {
|
||||||
|
override fun iterator(): Iterator<T> {
|
||||||
|
return CoalescingIterator(source.iterator(), merger)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CoalescingIterator<T>(private val source: Iterator<T>, private inline val merger: (T, T) -> T?) : Iterator<T> {
|
||||||
|
private var previous: T = if (source.hasNext()) source.next() else error("Please don’t pass empty iterators in here")
|
||||||
|
private var hasNext = true
|
||||||
|
|
||||||
|
override fun hasNext() = hasNext
|
||||||
|
|
||||||
|
override tailrec fun next(): T {
|
||||||
|
if (!source.hasNext()) {
|
||||||
|
hasNext = false
|
||||||
|
return previous
|
||||||
|
}
|
||||||
|
|
||||||
|
val current = source.next()
|
||||||
|
val merged = merger(previous, current)
|
||||||
|
// If the elements can’t be merged, return the first, then save the second for next time.
|
||||||
|
return if (merged == null) {
|
||||||
|
val ret = previous
|
||||||
|
previous = current
|
||||||
|
ret
|
||||||
|
} else {
|
||||||
|
previous = merged
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
src/test/kotlin/moe/kageru/sekwences/SekwencesTest.kt
Normal file
48
src/test/kotlin/moe/kageru/sekwences/SekwencesTest.kt
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package moe.kageru.sekwences
|
||||||
|
|
||||||
|
import io.kotlintest.shouldBe
|
||||||
|
import io.kotlintest.specs.ShouldSpec
|
||||||
|
|
||||||
|
class SekwencesTest : ShouldSpec({
|
||||||
|
"should merge numbers" {
|
||||||
|
val input = sequenceOf(1, 2, 3, 4, 5, 6, 4)
|
||||||
|
val output = input.coalesce { first, second ->
|
||||||
|
val sum = first + second
|
||||||
|
if (sum <= 10) sum else null
|
||||||
|
}.toList()
|
||||||
|
output shouldBe listOf(10, 5, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
"should merge collections" {
|
||||||
|
val input = sequenceOf("apple", "apricot", "banana", "peach", "pear", "plum")
|
||||||
|
val output = input.map { listOf(it) }.coalesce { first, second ->
|
||||||
|
if (first.first()[0] == second.first()[0]) {
|
||||||
|
first + second
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}.toList()
|
||||||
|
output shouldBe listOf(listOf("apple", "apricot"), listOf("banana"), listOf("peach", "pear", "plum"))
|
||||||
|
}
|
||||||
|
|
||||||
|
"should handle empty sequences" {
|
||||||
|
val input = emptySequence<Int>()
|
||||||
|
val output = input.coalesce { _, _ -> 0 }
|
||||||
|
output shouldBe emptySequence()
|
||||||
|
}
|
||||||
|
|
||||||
|
"should handle single elements" {
|
||||||
|
val input = sequenceOf(1)
|
||||||
|
val output = input.coalesce { a, b -> if (a > 5) a else b }.toList()
|
||||||
|
output shouldBe listOf(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
"should not modify sequences that can’t be merged" {
|
||||||
|
val input = listOf(6, 7, 34, 8)
|
||||||
|
val output = input.asSequence().coalesce { first, second ->
|
||||||
|
val sum = first + second
|
||||||
|
if (sum <= 10) sum else null
|
||||||
|
}.toList()
|
||||||
|
output shouldBe input
|
||||||
|
}
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user