From 31759f55d9fe904d2999f419b9e5510daf8838f9 Mon Sep 17 00:00:00 2001 From: Jun Sekine Date: Tue, 18 Apr 2023 01:12:47 +0900 Subject: [PATCH] add Iterable.crosswalk tests (#2894) --- .../commonMain/kotlin/arrow/core/Iterable.kt | 45 +++++++++++++++++++ .../kotlin/arrow/core/IterableTest.kt | 28 ++++++++++++ 2 files changed, 73 insertions(+) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt index 6e84455e566..be8129d5a43 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt @@ -1265,6 +1265,21 @@ public fun Iterable.fold(MA: Monoid): A = public fun Iterable.foldMap(MB: Monoid, f: (A) -> B): B = fold(MB.empty()) { acc, a -> MB.run { acc.combine(f(a)) } } +/** + * Applies function [f] to each element + * and returns a list for the applied result Iterable. + * + * ```kotlin + * import arrow.core.crosswalk + * import io.kotest.matchers.shouldBe + * + * fun test() { + * val ints = listOf(1, 2) + * val res = ints.crosswalk { i -> listOf("a${i}", "b${i}", "c${i}") } + * res shouldBe listOf(listOf("a2", "a1"), listOf("b2", "b1"), listOf("c2", "c1")) + * } + * ``` + */ public fun Iterable.crosswalk(f: (A) -> Iterable): List> = fold(emptyList()) { bs, a -> f(a).align(bs) { ior -> @@ -1276,6 +1291,21 @@ public fun Iterable.crosswalk(f: (A) -> Iterable): List> = } } +/** + * Applies function [f] to each element + * and returns the concatenated Map of the applied result Map. + * + * ```kotlin + * import arrow.core.crosswalk + * import io.kotest.matchers.shouldBe + * + * fun test() { + * val ints = listOf(1, 2) + * val res = ints.crosswalkMap { i -> mapOf("a" to i, "b" to i, "c" to i) } + * res shouldBe listOf("a", "b", "c").map { a -> a to ints.reversed() }.toMap() + * } + * ``` + */ public fun Iterable.crosswalkMap(f: (A) -> Map): Map> = fold(emptyMap()) { bs, a -> f(a).align(bs) { (_, ior) -> @@ -1287,6 +1317,21 @@ public fun Iterable.crosswalkMap(f: (A) -> Map): Map without null. + * + * ```kotlin + * import arrow.core.crosswalk + * import io.kotest.matchers.shouldBe + * + * fun test() { + * val ints = listOf(1, 2) + * val res = ints.crosswalkNull { i -> if (i % 2 == 0) "x${i}" else null } + * res shouldBe listOf("x2") + * } + * ``` + */ public fun Iterable.crosswalkNull(f: (A) -> B?): List? = fold?>(emptyList()) { bs, a -> Ior.fromNullables(f(a), bs)?.fold( diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt index b2ceab7d9b1..5753107745c 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt @@ -663,4 +663,32 @@ class IterableTest : StringSpec({ listOf(1,2,3).compareTo(listOf(1,1,3)) shouldBe 1 } + "crosswalk" { + checkAll(Arb.pair(Arb.list(Arb.int()), Arb.list(Arb.char()))) { (ints, chars) -> + val res = ints.crosswalk { i -> chars.map { c -> "${c}${i}" } } + val expected = + if (ints.isNotEmpty()) chars.map { c -> ints.reversed().map { i -> "${c}${i}" } } + else emptyList() + res shouldBe expected + } + } + + "crosswalkMap" { + checkAll(Arb.pair(Arb.list(Arb.int()), Arb.list(Arb.char()))) { (ints, chars) -> + val res = ints.crosswalkMap { i -> chars.map { c -> c to i }.toMap() } + val expected = + if (ints.isNotEmpty()) chars.map { c -> c to ints.reversed() }.toMap() + else emptyMap() + res shouldBe expected + } + } + + "crosswalkNull" { + checkAll(Arb.list(Arb.int())) { ints -> + val res = ints.crosswalkNull { i -> if (i % 2 == 0) "x${i}" else null } + val expected = ints.mapNotNull { i -> if (i % 2 == 0 ) "x${i}" else null }.reversed() + res shouldBe expected + } + } + })