Scan functions for Sequences and Iterable #KT-7657

This commit is contained in:
Abduqodiri Qurbonzoda
2020-01-24 04:42:19 +03:00
parent 0d7e641736
commit ed7b8e9b85
16 changed files with 2411 additions and 0 deletions
@@ -11,6 +11,7 @@ import test.assertStaticTypeIs
import test.assertTypeEquals
import test.collections.behaviors.*
import test.comparisons.STRING_CASE_INSENSITIVE_ORDER
import test.text.isAsciiLetter
import kotlin.test.*
import kotlin.random.Random
@@ -1073,6 +1074,161 @@ class ArraysTest {
expect(null, { intArrayOf().reduceRightOrNull { a, b -> a + b } })
}
@Test
fun scan() {
for (size in 0 until 4) {
val expected = listOf("", "0", "01", "012", "0123").take(size + 1)
// Array<T>
assertEquals(expected, Array(size) { it }.scan("") { acc, e -> acc + e })
// Primitive Arrays
assertEquals(expected, ByteArray(size) { it.toByte() }.scan("") { acc, e -> acc + e })
assertEquals(expected, CharArray(size) { '0' + it }.scan("") { acc, e -> acc + e })
assertEquals(expected, ShortArray(size) { it.toShort() }.scan("") { acc, e -> acc + e })
assertEquals(expected, IntArray(size) { it }.scan("") { acc, e -> acc + e })
assertEquals(expected, LongArray(size) { it.toLong() }.scan("") { acc, e -> acc + e })
assertEquals(expected, FloatArray(size) { it.toFloat() }.scan("") { acc, e -> acc + e.toInt() })
assertEquals(expected, DoubleArray(size) { it.toDouble() }.scan("") { acc, e -> acc + e.toInt() })
assertEquals(
expected.map { it.map { c -> c.toInt() % 2 == 0 }.joinToString(separator = "") },
BooleanArray(size) { it % 2 == 0 }.scan("") { acc, e -> acc + e }
)
}
}
@Test
fun scanIndexed() {
for (size in 0 until 4) {
val expected = listOf("+", "+[0: a]", "+[0: a][1: b]", "+[0: a][1: b][2: c]", "+[0: a][1: b][2: c][3: d]").take(size + 1)
// Array<T>
assertEquals(
expected,
Array(size) { 'a' + it }.scanIndexed("+") { index, acc, e -> "$acc[$index: $e]" }
)
// Primitive Arrays
assertEquals(
expected,
ByteArray(size) { it.toByte() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" }
)
assertEquals(
expected,
CharArray(size) { it.toChar() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" }
)
assertEquals(
expected,
ShortArray(size) { it.toShort() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" }
)
assertEquals(
expected,
IntArray(size) { it }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e}]" }
)
assertEquals(
expected,
LongArray(size) { it.toLong() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" }
)
assertEquals(
expected,
FloatArray(size) { it.toFloat() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" }
)
assertEquals(
expected,
DoubleArray(size) { it.toDouble() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" }
)
assertEquals(
expected.map { it.map { c -> if (c.isAsciiLetter()) c.toInt() % 2 != 0 else c }.joinToString(separator = "") },
BooleanArray(size) { it % 2 == 0 }.scanIndexed("+") { index, acc, e -> "$acc[$index: $e]" }
)
}
}
@Test
fun scanReduce() {
for (size in 0 until 4) {
val expected = listOf(0, 1, 3, 6).take(size)
// Array<T>
assertEquals(
expected,
Array(size) { it }.scanReduce { acc, e -> acc + e }
)
// Primitive Arrays
assertEquals(
expected.map { it.toByte() },
ByteArray(size) { it.toByte() }.scanReduce { acc, e -> (acc + e).toByte() }
)
assertEquals(
expected.map { it.toChar() },
CharArray(size) { it.toChar() }.scanReduce { acc, e -> acc + e.toInt() }
)
assertEquals(
expected.map { it.toShort() },
ShortArray(size) { it.toShort() }.scanReduce { acc, e -> (acc + e).toShort() }
)
assertEquals(
expected,
IntArray(size) { it }.scanReduce { acc, e -> acc + e }
)
assertEquals(
expected.map { it.toLong() },
LongArray(size) { it.toLong() }.scanReduce { acc, e -> acc + e }
)
assertEquals(
expected.map { it.toFloat() },
FloatArray(size) { it.toFloat() }.scanReduce { acc, e -> acc + e.toInt() }
)
assertEquals(
expected.map { it.toDouble() },
DoubleArray(size) { it.toDouble() }.scanReduce { acc, e -> acc + e.toInt() }
)
assertEquals(
expected.indices.map { it % 2 == 0 },
BooleanArray(size) { true }.scanReduce { acc, e -> acc != e }
)
}
}
@Test
fun scanReduceIndexed() {
for (size in 0 until 4) {
val expected = listOf(0, 1, 6, 27).take(size)
// Array<T>
assertEquals(
expected,
Array(size) { it }.scanReduceIndexed { index, acc, e -> index * (acc + e) }
)
// Primitive Arrays
assertEquals(
expected.map { it.toByte() },
ByteArray(size) { it.toByte() }.scanReduceIndexed { index, acc, e -> (index * (acc + e)).toByte() })
assertEquals(
expected.map { it.toChar() },
CharArray(size) { it.toChar() }.scanReduceIndexed { index, acc, e -> (index * (acc.toInt() + e.toInt())).toChar() }
)
assertEquals(
expected.map { it.toShort() },
ShortArray(size) { it.toShort() }.scanReduceIndexed { index, acc, e -> (index * (acc + e)).toShort() }
)
assertEquals(
expected,
IntArray(size) { it }.scanReduceIndexed { index, acc, e -> index * (acc + e) }
)
assertEquals(
expected.map { it.toLong() },
LongArray(size) { it.toLong() }.scanReduceIndexed { index, acc, e -> index * (acc + e) }
)
assertEquals(
expected.map { it.toFloat() },
FloatArray(size) { it.toFloat() }.scanReduceIndexed { index, acc, e -> index * (acc + e) }
)
assertEquals(
expected.map { it.toDouble() },
DoubleArray(size) { it.toDouble() }.scanReduceIndexed { index, acc, e -> index * (acc + e) }
)
assertEquals(
expected.indices.map { it % 2 == 0 },
BooleanArray(size) { true }.scanReduceIndexed { index, acc, e -> acc != e && index % 2 == 0 }
)
}
}
@Test fun reverseInPlace() {
fun <TArray, T> doTest(build: Iterable<Int>.() -> TArray, reverse: TArray.() -> Unit, snapshot: TArray.() -> List<T>) {
@@ -344,6 +344,38 @@ class CollectionTest {
expect(null, { arrayListOf<Int>().reduceRightOrNull { a, b -> a + b } })
}
@Test
fun scan() {
for (size in 0 until 4) {
val expected = listOf("", "0", "01", "012", "0123").take(size + 1)
assertEquals(expected, List(size) { it }.scan("") { acc, e -> acc + e })
}
}
@Test
fun scanIndexed() {
for (size in 0 until 4) {
val expected = listOf("+", "+[0: a]", "+[0: a][1: b]", "+[0: a][1: b][2: c]", "+[0: a][1: b][2: c][3: d]").take(size + 1)
assertEquals(expected, List(size) { 'a' + it }.scanIndexed("+") { index, acc, e -> "$acc[$index: $e]" })
}
}
@Test
fun scanReduce() {
for (size in 0 until 4) {
val expected = listOf(0, 1, 3, 6).take(size)
assertEquals(expected, List(size) { it }.scanReduce { acc, e -> acc + e })
}
}
@Test
fun scanReduceIndexed() {
for (size in 0 until 4) {
val expected = listOf(0, 1, 6, 27).take(size)
assertEquals(expected, List(size) { it }.scanReduceIndexed { index, acc, e -> index * (acc + e) })
}
}
@Test fun groupBy() {
val words = listOf("a", "abc", "ab", "def", "abcd")
val byLength = words.groupBy { it.length }
@@ -438,6 +438,40 @@ abstract class IterableTests<T : Iterable<String>>(val createFrom: (Array<out St
assertTrue(reduced == "foobar" || reduced == "barfoo")
}
@Test
fun scan() {
val accumulators = data.scan("baz") { acc, e -> acc + e }
assertEquals(3, accumulators.size)
assertEquals("baz", accumulators.first())
assertTrue(accumulators.elementAt(1) in listOf("bazfoo", "bazbar"))
assertTrue(accumulators.last() in listOf("bazfoobar", "bazbarfoo"))
}
@Test
fun scanIndexed() {
val accumulators = data.scanIndexed("baz") { i, acc, e -> acc + i + e }
assertEquals(3, accumulators.size)
assertEquals("baz", accumulators.first())
assertTrue(accumulators.elementAt(1) in listOf("baz0foo", "baz0bar"))
assertTrue(accumulators.last() in listOf("baz0foo1bar", "baz0bar1foo"))
}
@Test
fun scanReduce() {
val accumulators = data.scanReduce { acc, e -> acc + e }
assertEquals(2, accumulators.size)
assertTrue(accumulators.first() in listOf("foo", "bar"))
assertTrue(accumulators.last() in listOf("foobar", "barfoo"))
}
@Test
fun scanReduceIndexed() {
val accumulators = data.scanReduceIndexed { i, acc, e -> acc + i + e }
assertEquals(2, accumulators.size)
assertTrue(accumulators.first() in listOf("foo", "bar"))
assertTrue(accumulators.last() in listOf("foo1bar", "bar1foo"))
}
@Test
fun mapAndJoinToString() {
val result = data.joinToString(separator = "-") { it.toUpperCase() }
@@ -13,6 +13,8 @@ fun fibonacci(): Sequence<Int> {
return generateSequence(Pair(0, 1), { Pair(it.second, it.first + it.second) }).map { it.first * 1 }
}
fun indexSequence(): Sequence<Int> = generateSequence(0) { it + 1 }
public class SequenceTest {
private class TriggerSequence<out T>(val source: Sequence<T>) : Sequence<T> {
@@ -145,6 +147,47 @@ public class SequenceTest {
assertEquals("13, 21, 34, 55, 89, ...", fibonacci().filter { it > 10 }.joinToString(separator = ", ", limit = 5))
}
@Test
fun scan() {
for (size in 0 until 4) {
assertEquals(
sequenceOf("", "0", "01", "012").take(size).toList(),
indexSequence().scan("") { acc, e -> acc + e }.take(size).toList()
)
}
}
@Test
fun scanIndexed() {
for (size in 0 until 4) {
assertEquals(
sequenceOf("+", "+[0: a]", "+[0: a][1: b]", "+[0: a][1: b][2: c]").take(size).toList(),
indexSequence().map { 'a' + it }.scanIndexed("+") { index, acc, e -> "$acc[$index: $e]" }.take(size).toList()
)
}
}
@Test
fun scanReduce() {
for (size in 0 until 4) {
val expected = listOf(0, 1, 3, 6).subList(0, size)
assertEquals(
sequenceOf(0, 1, 3, 6).take(size).toList(),
indexSequence().scanReduce { acc, e -> acc + e }.take(size).toList()
)
}
}
@Test
fun scanReduceIndexed() {
for (size in 0 until 4) {
assertEquals(
sequenceOf(0, 1, 6, 27).take(size).toList(),
indexSequence().scanReduceIndexed { index, acc, e -> index * (acc + e) }.take(size).toList()
)
}
}
@Test fun drop() {
assertEquals(emptyList(), emptySequence<Int>().drop(1).toList())
listOf(2, 3, 4, 5).let { assertEquals(it, it.asSequence().drop(0).toList()) }
@@ -635,6 +635,86 @@ class UnsignedArraysTest {
expect(" 2-3 1-2 0-1") { ulongArrayOf(1, 2, 3).foldRightIndexed("") { i, e, acc -> "$acc $i-$e" } }
}
@Test
fun scan() {
for (size in 0 until 4) {
val expected = listOf("", "0", "01", "012", "0123").subList(0, size + 1)
assertEquals(expected, UByteArray(size) { it.toUByte() }.scan("") { acc, e -> acc + e })
assertEquals(expected, UShortArray(size) { it.toUShort() }.scan("") { acc, e -> acc + e })
assertEquals(expected, UIntArray(size) { it.toUInt() }.scan("") { acc, e -> acc + e })
assertEquals(expected, ULongArray(size) { it.toULong() }.scan("") { acc, e -> acc + e })
}
}
@Test
fun scanIndexed() {
for (size in 0 until 4) {
val expected = listOf("+", "+[0: a]", "+[0: a][1: b]", "+[0: a][1: b][2: c]", "+[0: a][1: b][2: c][3: d]").subList(0, size + 1)
assertEquals(
expected,
UByteArray(size) { it.toUByte() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" }
)
assertEquals(
expected,
UShortArray(size) { it.toUShort() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" }
)
assertEquals(
expected,
UIntArray(size) { it.toUInt() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" }
)
assertEquals(
expected,
ULongArray(size) { it.toULong() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" }
)
}
}
@Test
fun scanReduce() {
for (size in 0 until 4) {
val expected = listOf(0, 1, 3, 6).subList(0, size)
assertEquals(
expected.map { it.toUByte() },
UByteArray(size) { it.toUByte() }.scanReduce { acc, e -> (acc + e).toUByte() }
)
assertEquals(
expected.map { it.toUShort() },
UShortArray(size) { it.toUShort() }.scanReduce { acc, e -> (acc + e).toUShort() }
)
assertEquals(
expected.map { it.toUInt() },
UIntArray(size) { it.toUInt() }.scanReduce { acc, e -> acc + e }
)
assertEquals(
expected.map { it.toULong() },
ULongArray(size) { it.toULong() }.scanReduce { acc, e -> acc + e }
)
}
}
@Test
fun scanReduceIndexed() {
for (size in 0 until 4) {
val expected = listOf(0, 1, 6, 27).subList(0, size)
assertEquals(
expected.map { it.toUByte() },
UByteArray(size) { it.toUByte() }.scanReduceIndexed { index, acc, e -> (index.toUInt() * (acc + e)).toUByte() }
)
assertEquals(
expected.map { it.toUShort() },
UShortArray(size) { it.toUShort() }.scanReduceIndexed { index, acc, e -> (index.toUInt() * (acc + e)).toUShort() }
)
assertEquals(
expected.map { it.toUInt() },
UIntArray(size) { it.toUInt() }.scanReduceIndexed { index, acc, e -> index.toUInt() * (acc + e) }
)
assertEquals(
expected.map { it.toULong() },
ULongArray(size) { it.toULong() }.scanReduceIndexed { index, acc, e -> index.toULong() * (acc + e) }
)
}
}
@Test
fun elementAt() {
expect(0u) { ubyteArrayOf(0, 1, 2).elementAt(0) }
+41
View File
@@ -1311,6 +1311,47 @@ class StringTest {
expect(null, { arg1("").reduceOrNull { _, _ -> '\n' } })
}
@Test
fun scan() = withOneCharSequenceArg { arg1 ->
for (size in 0 until 4) {
assertEquals(
listOf("", "0", "01", "012", "0123").take(size + 1),
arg1((0 until size).joinToString(separator = "")).scan("") { acc, e -> acc + e }
)
}
}
@Test
fun scanIndexed() = withOneCharSequenceArg { arg1 ->
for (size in 0 until 4) {
assertEquals(
listOf("+", "+[0: a]", "+[0: a][1: b]", "+[0: a][1: b][2: c]", "+[0: a][1: b][2: c][3: d]").take(size + 1),
arg1(('a' until 'a' + size).joinToString(separator = "")).scanIndexed("+") { index, acc, e -> "$acc[$index: $e]" }
)
}
}
@Test
fun scanReduce() = withOneCharSequenceArg { arg1 ->
for (size in 0 until 4) {
assertEquals(
listOf(0, 1, 3, 6).take(size).map { it.toChar() },
arg1((0.toChar() until size.toChar()).joinToString(separator = "")).scanReduce { acc, e -> acc + e.toInt() }
)
}
}
@Test
fun scanReduceIndexed() = withOneCharSequenceArg { arg1 ->
for (size in 0 until 4) {
assertEquals(
listOf(0, 1, 6, 27).take(size).map { it.toChar() },
arg1((0.toChar() until size.toChar()).joinToString(separator = "")).scanReduceIndexed { index, acc, e -> (index * (acc.toInt() + e.toInt())).toChar() }
)
}
}
@Test fun groupBy() = withOneCharSequenceArg("abAbaABcD") { data ->
// group characters by their case
val result = data.groupBy { it.isAsciiUpperCase() }