
commonMain.space.kscience.dataforge.data.dataTransform.kt Maven / Gradle / Ivy
package space.kscience.dataforge.data
import kotlinx.coroutines.flow.*
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.seal
import space.kscience.dataforge.meta.toMutableMeta
import space.kscience.dataforge.misc.DFInternal
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* Lazily transform this data to another data. By convention [block] should not use external data (be pure).
* @param coroutineContext additional [CoroutineContext] elements used for data computation.
* @param meta for the resulting data. By default equals input data.
* @param block the transformation itself
*/
public inline fun Data.map(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = this.meta,
crossinline block: suspend (T) -> R,
): Data = Data(meta, coroutineContext, listOf(this)) {
block(await())
}
/**
* Combine this data with the other data using [block]. See [map] for other details
*/
public inline fun Data.combine(
other: Data,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = this.meta,
crossinline block: suspend (left: T1, right: T2) -> R,
): Data = Data(meta, coroutineContext, listOf(this, other)) {
block(await(), other.await())
}
//data collection operations
/**
* Lazily reduce a collection of [Data] to a single data.
*/
public inline fun Collection>.reduceToData(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
crossinline block: suspend (Collection) -> R,
): Data = Data(
meta,
coroutineContext,
this
) {
block(map { it.await() })
}
@DFInternal
public fun Map>.reduceToData(
outputType: KType,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
block: suspend (Map) -> R,
): Data = Data(
outputType,
meta,
coroutineContext,
this.values
) {
block(mapValues { it.value.await() })
}
/**
* Lazily reduce a [Map] of [Data] with any static key.
* @param K type of the map key
* @param T type of the input goal
* @param R type of the result goal
*/
public inline fun Map>.reduceToData(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
noinline block: suspend (Map) -> R,
): Data = Data(
meta,
coroutineContext,
this.values
) {
block(mapValues { it.value.await() })
}
//flow operations
/**
* Transform a [Flow] of [NamedData] to a single [Data].
*/
@DFInternal
public suspend fun Flow>.reduceToData(
outputType: KType,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
transformation: suspend (Flow>) -> R,
): Data = Data(
outputType,
meta,
coroutineContext,
toList()
) {
transformation(this)
}
@OptIn(DFInternal::class)
public suspend inline fun Flow>.reduceToData(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
noinline transformation: suspend (Flow>) -> R,
): Data = reduceToData(typeOf(), coroutineContext, meta) {
transformation(it)
}
/**
* Fold a flow of named data into a single [Data]
*/
public suspend inline fun Flow>.foldToData(
initial: R,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
noinline block: suspend (result: R, data: NamedData) -> R,
): Data = reduceToData(
coroutineContext, meta
) {
it.fold(initial, block)
}
//DataSet operations
@DFInternal
public suspend fun DataSet.map(
outputType: KType,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
metaTransform: MutableMeta.() -> Unit = {},
block: suspend (T) -> R,
): DataTree = DataTree(outputType) {
populate(
flow().map {
val newMeta = it.meta.toMutableMeta().apply(metaTransform).seal()
Data(outputType, newMeta, coroutineContext, listOf(it)) {
block(it.await())
}.named(it.name)
}
)
}
@OptIn(DFInternal::class)
public suspend inline fun DataSet.map(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
noinline metaTransform: MutableMeta.() -> Unit = {},
noinline block: suspend (T) -> R,
): DataTree = map(typeOf(), coroutineContext, metaTransform, block)
public suspend fun DataSet.forEach(block: suspend (NamedData) -> Unit) {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
flow().collect {
block(it)
}
}
public suspend inline fun DataSet.reduceToData(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
noinline transformation: suspend (Flow>) -> R,
): Data = flow().reduceToData(coroutineContext, meta, transformation)
public suspend inline fun DataSet.foldToData(
initial: R,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
noinline block: suspend (result: R, data: NamedData) -> R,
): Data = flow().foldToData(initial, coroutineContext, meta, block)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy