
commonMain.arrow.core.map.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of arrow-core Show documentation
Show all versions of arrow-core Show documentation
Functional companion to Kotlin's Standard Library
@file:OptIn(ExperimentalTypeInference::class)
package arrow.core
import arrow.core.raise.either
import arrow.core.raise.mapOrAccumulate
import arrow.core.raise.RaiseAccumulate
import arrow.core.raise.mapValuesOrAccumulate
import kotlin.experimental.ExperimentalTypeInference
/**
* Combines to structures by taking the intersection of their shapes
* and using `Pair` to hold the elements.
*
* ```kotlin
* import arrow.core.zip
* import io.kotest.matchers.shouldBe
*
* fun test() {
* mapOf(1 to "A", 2 to "B")
* .zip(mapOf(1 to "1", 2 to "2", 3 to "3")) shouldBe mapOf(1 to Pair("A", "1"), 2 to Pair("B", "2"))
* }
* ```
*
*
*/
public fun Map.zip(other: Map): Map> =
zip(other) { _, a, b -> Pair(a, b) }
/**
* Combines to structures by taking the intersection of their shapes
* and combining the elements with the given function.
*
* ```kotlin
* import arrow.core.zip
* import io.kotest.matchers.shouldBe
*
* fun test() {
* mapOf(1 to "A", 2 to "B").zip(mapOf(1 to "1", 2 to "2", 3 to "3")) {
* _, a, b -> "$a ~ $b"
* } shouldBe mapOf(1 to "A ~ 1", 2 to "B ~ 2")
* }
* ```
*
*
*/
@Suppress("UNCHECKED_CAST")
public inline fun Map.zip(other: Map, map: (Key, A, B) -> C): Map =
buildMap(size) {
[email protected] { (key, bb) ->
if (other.containsKey(key)) {
put(key, map(key, bb, other[key] as B))
}
}
}
@Suppress("UNCHECKED_CAST")
public inline fun Map.zip(
c: Map,
d: Map,
map: (Key, B, C, D) -> E
): Map = buildMap(size) {
[email protected] { (key, bb) ->
if (c.containsKey(key) && d.containsKey(key)) {
val cc = c[key] as C
val dd = d[key] as D
put(key, map(key, bb, cc, dd))
}
}
}
@Suppress("UNCHECKED_CAST")
public inline fun Map.zip(
c: Map,
d: Map,
e: Map,
map: (Key, B, C, D, E) -> F
): Map = buildMap(size) {
[email protected] { (key, bb) ->
if (c.containsKey(key) && d.containsKey(key) && e.containsKey(key)) {
val cc = c[key] as C
val dd = d[key] as D
val ee = e[key] as E
put(key, map(key, bb, cc, dd, ee))
}
}
}
@Suppress("UNCHECKED_CAST")
public inline fun Map.zip(
c: Map,
d: Map,
e: Map,
f: Map,
map: (Key, B, C, D, E, F) -> G
): Map = buildMap(size) {
[email protected] { (key, bb) ->
if (c.containsKey(key) && d.containsKey(key) && e.containsKey(key) && f.containsKey(key)) {
val cc = c[key] as C
val dd = d[key] as D
val ee = e[key] as E
val ff = f[key] as F
put(key, map(key, bb, cc, dd, ee, ff))
}
}
}
@Suppress("UNCHECKED_CAST")
public inline fun Map.zip(
c: Map,
d: Map,
e: Map,
f: Map,
g: Map,
map: (Key, B, C, D, E, F, G) -> H
): Map = buildMap(size) {
[email protected] { (key, bb) ->
if (c.containsKey(key) && d.containsKey(key) && e.containsKey(key) && f.containsKey(key) && g.containsKey(key)) {
val cc = c[key] as C
val dd = d[key] as D
val ee = e[key] as E
val ff = f[key] as F
val gg = g[key] as G
put(key, map(key, bb, cc, dd, ee, ff, gg))
}
}
}
@Suppress("UNCHECKED_CAST")
public inline fun Map.zip(
c: Map,
d: Map,
e: Map,
f: Map,
g: Map,
h: Map,
map: (Key, B, C, D, E, F, G, H) -> I
): Map = buildMap(size) {
[email protected] { (key, bb) ->
if (c.containsKey(key) && d.containsKey(key) && e.containsKey(key) && f.containsKey(key) && g.containsKey(key) && h.containsKey(key)) {
val cc = c[key] as C
val dd = d[key] as D
val ee = e[key] as E
val ff = f[key] as F
val gg = g[key] as G
val hh = h[key] as H
put(key, map(key, bb, cc, dd, ee, ff, gg, hh))
}
}
}
@Suppress("UNCHECKED_CAST")
public inline fun Map.zip(
c: Map,
d: Map,
e: Map,
f: Map,
g: Map,
h: Map,
i: Map,
map: (Key, B, C, D, E, F, G, H, I) -> J
): Map = buildMap(size) {
[email protected] { (key, bb) ->
if (c.containsKey(key) && d.containsKey(key) && e.containsKey(key) && f.containsKey(key) && g.containsKey(key) && h.containsKey(key) && i.containsKey(key)) {
val cc = c[key] as C
val dd = d[key] as D
val ee = e[key] as E
val ff = f[key] as F
val gg = g[key] as G
val hh = h[key] as H
val ii = i[key] as I
put(
key, map(key, bb, cc, dd, ee, ff, gg, hh, ii)
)
}
}
}
@Suppress("UNCHECKED_CAST")
public inline fun Map.zip(
c: Map,
d: Map,
e: Map,
f: Map,
g: Map,
h: Map,
i: Map,
j: Map,
map: (Key, B, C, D, E, F, G, H, I, J) -> K
): Map = buildMap(size) {
[email protected] { (key, bb) ->
if (c.containsKey(key) && d.containsKey(key) && e.containsKey(key) && f.containsKey(key) && g.containsKey(key) && h.containsKey(key) && i.containsKey(key) && j.containsKey(key)) {
val cc = c[key] as C
val dd = d[key] as D
val ee = e[key] as E
val ff = f[key] as F
val gg = g[key] as G
val hh = h[key] as H
val ii = i[key] as I
val jj = j[key] as J
put(key, map(key, bb, cc, dd, ee, ff, gg, hh, ii, jj))
}
}
}
@Suppress("UNCHECKED_CAST")
public inline fun Map.zip(
c: Map,
d: Map,
e: Map,
f: Map,
g: Map,
h: Map,
i: Map,
j: Map,
k: Map,
map: (Key, B, C, D, E, F, G, H, I, J, K) -> L
): Map = buildMap(size) {
[email protected] { (key, bb) ->
if (c.containsKey(key) && d.containsKey(key) && e.containsKey(key) && f.containsKey(key) && g.containsKey(key) && h.containsKey(key) && i.containsKey(key) && j.containsKey(key) && k.containsKey(key)) {
val cc = c[key] as C
val dd = d[key] as D
val ee = e[key] as E
val ff = f[key] as F
val gg = g[key] as G
val hh = h[key] as H
val ii = i[key] as I
val jj = j[key] as J
val kk = k[key] as K
put(key, map(key, bb, cc, dd, ee, ff, gg, hh, ii, jj, kk))
}
}
}
/**
* Transform every [Map.Entry] of the original [Map] using [f],
* only keeping the [Map.Entry] of the transformed map that match the input [Map.Entry].
*/
@Suppress("UNCHECKED_CAST")
public fun Map.flatMapValues(f: (Map.Entry) -> Map): Map =
buildMap {
[email protected] { entry ->
val nestedMap = f(entry)
if (nestedMap.containsKey(entry.key)) {
put(entry.key, nestedMap[entry.key] as B)
}
}
}
@Deprecated(
message = "Deprecated to allow for future alignment with stdlib Map#map returning List",
replaceWith = ReplaceWith("mapValuesOrAccumulate(combine, transform)"),
)
public inline fun Map.mapOrAccumulate(
combine: (E, E) -> E,
@BuilderInference transform: RaiseAccumulate.(Map.Entry) -> B
): Either> = mapValuesOrAccumulate(combine, transform)
@Deprecated(
message = "Deprecated to allow for future alignment with stdlib Map#map returning List",
replaceWith = ReplaceWith("mapValuesOrAccumulate(transform)"),
)
public inline fun Map.mapOrAccumulate(
@BuilderInference transform: RaiseAccumulate.(Map.Entry) -> B
): Either, Map> = mapValuesOrAccumulate(transform)
public inline fun Map.mapValuesOrAccumulate(
combine: (E, E) -> E,
@BuilderInference transform: RaiseAccumulate.(Map.Entry) -> B
): Either> = either {
mapValuesOrAccumulate(this@mapValuesOrAccumulate, combine, transform)
}
public inline fun Map.mapValuesOrAccumulate(
@BuilderInference transform: RaiseAccumulate.(Map.Entry) -> B
): Either, Map> = either {
mapValuesOrAccumulate(this@mapValuesOrAccumulate, transform)
}
public inline fun Map.mapValuesNotNull(transform: (Map.Entry) -> B?): Map =
buildMap {
[email protected] { entry ->
transform(entry)?.let { put(entry.key, it) }
}
}
public fun Map>.filterOption(): Map =
buildMap {
[email protected] { (key, option) ->
option.fold({ }, { put(key, it) })
}
}
/**
* Returns a Map containing all elements that are instances of specified type parameter R.
*/
@Suppress("UNCHECKED_CAST")
public inline fun Map.filterIsInstance(): Map =
filterValues { it is R } as Map
/**
* Combines two structures by taking the union of their shapes and using Ior to hold the elements.
*
* ```kotlin
* import arrow.core.*
* import io.kotest.matchers.shouldBe
*
* fun test() {
* val res = mapOf(1 to 1, 2 to 2).align(mapOf(1 to "1", 2 to "2", 3 to "3"))
* res shouldBe mapOf(1 to Ior.Both(1, "1"), 2 to Ior.Both(2, "2"), 3 to Ior.Right("3"))
* }
* ```
*
*
*/
public fun Map.align(b: Map): Map> =
padZip(b, { _, a -> Ior.Left(a) }, { _, bb -> Ior.Right(bb) }) { _, a, bb -> Ior.Both(a, bb) }
/**
* Combines two structures by taking the union of their shapes and combining the elements with the given function.
*
* ```kotlin
* import arrow.core.*
* import io.kotest.matchers.shouldBe
*
* fun test() {
* mapOf("1" to 1, "2" to 2)
* .align(mapOf("1" to 1, "2" to 2, "3" to 3)) { (_, a) ->
* "$a"
* } shouldBe mapOf("1" to "Ior.Both(1, 1)", "2" to Ior.Both(2, 2), "3" to Ior.Right(3))
* }
* ```
*
*
*/
public fun Map.align(b: Map, fa: (Map.Entry>) -> C): Map =
padZip(
b,
{ k, a -> fa(Entry(k, Ior.Left(a))) },
{ k, bb -> fa(Entry(k, Ior.Right(bb))) }
) { k, a, bb -> fa(Entry(k, Ior.Both(a, bb))) }
private class Entry(override val key: K, override val value: V) : Map.Entry {
override fun hashCode(): Int = key.hashCode() xor value.hashCode()
override fun toString(): String = "$key=$value"
override fun equals(other: Any?): Boolean =
other is Map.Entry<*, *> && other.key == key && other.value == value
}
public fun Map.salign(other: Map, combine: (A, A) -> A): Map =
padZip(other, { _, a -> a }, { _, b -> b }) { _, a, b -> combine(a, b) }
/**
* Align two structures as in zip, but filling in blanks with null.
*/
public fun Map.padZip(other: Map): Map> =
padZip(other) { _, a, b -> a to b }
public fun Map.padZip(other: Map, fa: (K, A?, B?) -> C): Map =
padZip(other, { k, a -> fa(k, a, null) }, { k, b -> fa(k, null, b) }) { k, a, b -> fa(k, a, b) }
@Suppress("UNCHECKED_CAST")
public inline fun Map.padZip(
other: Map,
left: (K, A) -> C,
right: (K, B) -> C,
both: (K, A, B) -> C
): Map = buildMap {
([email protected] + other.keys).forEach { key ->
when {
[email protected](key) && other.containsKey(key) ->
put(key, both(key, this@padZip[key] as A, other[key] as B))
[email protected](key) -> put(key, left(key, this@padZip[key] as A))
other.containsKey(key) -> put(key, right(key, other[key] as B))
}
}
}
/**
* Splits a union into its component parts.
*
* ```kotlin
* import arrow.core.*
* import io.kotest.matchers.shouldBe
*
* fun test() {
* mapOf(
* "first" to Ior.Both("A", 1),
* "second" to Ior.Both("B", 2),
* "third" to Ior.Left("C")
* ).unalign() shouldBe Pair(mapOf("first" to "A", "second" to "B", "third" to "C"), mapOf("first" to 1, "second" to 2))
* }
* ```
*
*
*/
public fun Map>.unalign(): Pair
© 2015 - 2025 Weber Informatics LLC | Privacy Policy