diff --git a/core/api/core.api b/core/api/core.api index 59cb6d44ab..64b04c6b20 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -315,6 +315,7 @@ public final class org/jetbrains/kotlinx/dataframe/api/AddDsl : org/jetbrains/ko public fun getColumnOrNull (Lkotlin/reflect/KProperty;)Lorg/jetbrains/kotlinx/dataframe/DataColumn; public fun getColumnOrNull (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnPath;)Lorg/jetbrains/kotlinx/dataframe/DataColumn; public fun getColumnOrNull (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;)Lorg/jetbrains/kotlinx/dataframe/DataColumn; + public final fun getColumns ()Ljava/util/List; public final fun getDf ()Lorg/jetbrains/kotlinx/dataframe/DataFrame; public final fun group (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V public final fun group (Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlinx/dataframe/api/AddGroup; @@ -593,8 +594,14 @@ public abstract interface class org/jetbrains/kotlinx/dataframe/api/AllExceptCol public final class org/jetbrains/kotlinx/dataframe/api/AllKt { public static final fun all (Lorg/jetbrains/kotlinx/dataframe/DataColumn;Lkotlin/jvm/functions/Function1;)Z public static final fun all (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;)Z + public static final fun allAfterInternal (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnsResolver;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlinx/dataframe/columns/ColumnSet; + public static final fun allBeforeInternal (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnsResolver;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlinx/dataframe/columns/ColumnSet; + public static final fun allColumnsInternal (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnsResolver;Z)Lorg/jetbrains/kotlinx/dataframe/impl/columns/TransformableColumnSet; + public static synthetic fun allColumnsInternal$default (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnsResolver;ZILjava/lang/Object;)Lorg/jetbrains/kotlinx/dataframe/impl/columns/TransformableColumnSet; + public static final fun allFromInternal (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnsResolver;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlinx/dataframe/columns/ColumnSet; public static final fun allNA (Lorg/jetbrains/kotlinx/dataframe/DataRow;)Z public static final fun allNulls (Lorg/jetbrains/kotlinx/dataframe/DataColumn;)Z + public static final fun allUpToInternal (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnsResolver;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlinx/dataframe/columns/ColumnSet; } public abstract interface class org/jetbrains/kotlinx/dataframe/api/AndColumnsSelectionDsl { @@ -1024,6 +1031,10 @@ public abstract interface class org/jetbrains/kotlinx/dataframe/api/ColsInGroups public abstract interface class org/jetbrains/kotlinx/dataframe/api/ColsInGroupsColumnsSelectionDsl$Grammar$PlainDslName { } +public final class org/jetbrains/kotlinx/dataframe/api/ColsKt { + public static final fun colsInternal (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnsResolver;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlinx/dataframe/impl/columns/TransformableColumnSet; +} + public abstract interface class org/jetbrains/kotlinx/dataframe/api/ColsOfColumnsSelectionDsl { public fun colsOf (Ljava/lang/String;Lkotlin/reflect/KType;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlinx/dataframe/columns/ColumnSet; public fun colsOf (Lkotlin/reflect/KProperty;Lkotlin/reflect/KType;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlinx/dataframe/columns/ColumnSet; @@ -3867,6 +3878,8 @@ public final class org/jetbrains/kotlinx/dataframe/api/SortKt { public final class org/jetbrains/kotlinx/dataframe/api/Split { public fun (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;)V public final fun cast ()Lorg/jetbrains/kotlinx/dataframe/api/Split; + public final fun getColumns ()Lkotlin/jvm/functions/Function2; + public final fun getDf ()Lorg/jetbrains/kotlinx/dataframe/DataFrame; public fun toString ()Ljava/lang/String; } @@ -4829,6 +4842,10 @@ public abstract interface class org/jetbrains/kotlinx/dataframe/columns/BaseColu public abstract fun values ()Ljava/lang/Iterable; } +public final class org/jetbrains/kotlinx/dataframe/columns/BaseColumnKt { + public static final fun getValues (Lorg/jetbrains/kotlinx/dataframe/columns/BaseColumn;)Ljava/lang/Iterable; +} + public abstract interface class org/jetbrains/kotlinx/dataframe/columns/ColumnAccessor : org/jetbrains/kotlinx/dataframe/columns/ColumnReference { public abstract fun get (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;)Lorg/jetbrains/kotlinx/dataframe/columns/ColumnAccessor; public fun getValue (Ljava/lang/Object;Lkotlin/reflect/KProperty;)Lorg/jetbrains/kotlinx/dataframe/columns/ColumnAccessor; @@ -5540,6 +5557,14 @@ public final class org/jetbrains/kotlinx/dataframe/impl/api/ConvertToKt { public static synthetic fun convertToImpl$default (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/reflect/KType;ZLorg/jetbrains/kotlinx/dataframe/api/ExcessiveColumns;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; } +public final class org/jetbrains/kotlinx/dataframe/impl/api/DuplicateKt { + public static final fun duplicateRowsImpl (Lorg/jetbrains/kotlinx/dataframe/DataFrame;ILjava/lang/Iterable;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; +} + +public final class org/jetbrains/kotlinx/dataframe/impl/api/GroupByKt { + public static final fun groupByImpl (Lorg/jetbrains/kotlinx/dataframe/DataFrame;ZLkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/api/GroupBy; +} + public final class org/jetbrains/kotlinx/dataframe/impl/api/InsertKt { public static final fun insertImpl (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lorg/jetbrains/kotlinx/dataframe/columns/ColumnPath;Lorg/jetbrains/kotlinx/dataframe/DataColumn;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; } @@ -5658,6 +5683,7 @@ public abstract interface class org/jetbrains/kotlinx/dataframe/impl/columns/Tra public final class org/jetbrains/kotlinx/dataframe/impl/columns/UtilsKt { public static final fun asAnyFrameColumn (Lorg/jetbrains/kotlinx/dataframe/DataColumn;)Lorg/jetbrains/kotlinx/dataframe/columns/FrameColumn; + public static final fun transform (Lorg/jetbrains/kotlinx/dataframe/columns/ColumnsResolver;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlinx/dataframe/impl/columns/TransformableColumnSet; } public final class org/jetbrains/kotlinx/dataframe/impl/io/FastDoubleParser { diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/DataRowApi.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/DataRowApi.kt index 4b4ee8baed..b65cd86d1b 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/DataRowApi.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/DataRowApi.kt @@ -111,7 +111,7 @@ internal interface DiffOrNullDocs */ @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType -public fun DataRow.diff(firstRowResult: Double, expression: RowExpression): Double = +public inline fun DataRow.diff(firstRowResult: Double, expression: RowExpression): Double = prev()?.let { p -> expression(this, this) - expression(p, p) } ?: firstRowResult @@ -121,21 +121,21 @@ public fun DataRow.diff(firstRowResult: Double, expression: RowExpression @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType // required to resolve `diff(0) { intValue }` -public fun DataRow.diff(firstRowResult: Int, expression: RowExpression): Int = +public inline fun DataRow.diff(firstRowResult: Int, expression: RowExpression): Int = prev()?.let { p -> expression(this, this) - expression(p, p) } ?: firstRowResult /** * @include [DiffDocs] */ -public fun DataRow.diff(firstRowResult: Long, expression: RowExpression): Long = +public inline fun DataRow.diff(firstRowResult: Long, expression: RowExpression): Long = prev()?.let { p -> expression(this, this) - expression(p, p) } ?: firstRowResult /** * @include [DiffDocs] */ -public fun DataRow.diff(firstRowResult: Float, expression: RowExpression): Float = +public inline fun DataRow.diff(firstRowResult: Float, expression: RowExpression): Float = prev()?.let { p -> expression(this, this) - expression(p, p) } ?: firstRowResult @@ -144,25 +144,25 @@ public fun DataRow.diff(firstRowResult: Float, expression: RowExpression< */ @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType -public fun DataRow.diffOrNull(expression: RowExpression): Double? = +public inline fun DataRow.diffOrNull(expression: RowExpression): Double? = prev()?.let { p -> expression(this, this) - expression(p, p) } /** * @include [DiffOrNullDocs] */ -public fun DataRow.diffOrNull(expression: RowExpression): Int? = +public inline fun DataRow.diffOrNull(expression: RowExpression): Int? = prev()?.let { p -> expression(this, this) - expression(p, p) } /** * @include [DiffOrNullDocs] */ -public fun DataRow.diffOrNull(expression: RowExpression): Long? = +public inline fun DataRow.diffOrNull(expression: RowExpression): Long? = prev()?.let { p -> expression(this, this) - expression(p, p) } /** * @include [DiffOrNullDocs] */ -public fun DataRow.diffOrNull(expression: RowExpression): Float? = +public inline fun DataRow.diffOrNull(expression: RowExpression): Float? = prev()?.let { p -> expression(this, this) - expression(p, p) } public fun AnyRow.columnsCount(): Int = df().ncol @@ -205,7 +205,7 @@ public fun DataRow.relative(relativeIndices: IntRange): DataFrame = (relativeIndices.first + index).coerceIn(df().indices)..(relativeIndices.last + index).coerceIn(df().indices), ) -public fun DataRow.movingAverage(k: Int, expression: RowExpression): Double { +public inline fun DataRow.movingAverage(k: Int, expression: RowExpression): Double { var count = 0 return backwardIterable().take(k).sumOf { count++ diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/add.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/add.kt index f0f8ae06e0..9161563017 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/add.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/add.kt @@ -166,7 +166,8 @@ public class AddDsl( ColumnSelectionDsl { // TODO: support adding column into path - internal val columns = mutableListOf() + @PublishedApi + internal val columns: MutableList = mutableListOf() public fun add(column: AnyColumnReference): Boolean = columns.add(column.resolveSingle(df)!!.data) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/all.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/all.kt index 6198ecb17d..319abd66fb 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/all.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/all.kt @@ -52,7 +52,7 @@ public fun AnyRow.allNA(): Boolean = owner.columns().all { it[index()].isNA } // region DataFrame /** Returns `true` if all [rows] match the given [predicate] or [rows] is empty. */ -public fun DataFrame.all(predicate: RowFilter): Boolean = rows().all { predicate(it, it) } +public inline fun DataFrame.all(predicate: RowFilter): Boolean = rows().all { predicate(it, it) } // endregion @@ -1204,6 +1204,7 @@ public interface AllColumnsSelectionDsl { * else it simply returns a [(transformable) ColumnSet][TransformableColumnSet] from [this] * (like when [this] is a [ColumnSet]). */ +@PublishedApi internal fun ColumnsResolver<*>.allColumnsInternal(removePaths: Boolean = false): TransformableColumnSet<*> = transform { cols -> if (this is SingleColumn<*> && cols.singleOrNull()?.isColumnGroup() == true) { @@ -1225,7 +1226,8 @@ internal fun ColumnsResolver<*>.allColumnsInternal(removePaths: Boolean = false) * @param colByPredicate a function that takes a ColumnWithPath and returns true if the column matches the predicate, false otherwise * @return a new ColumnSet containing all columns after the first column that matches the given predicate */ -internal fun ColumnsResolver<*>.allAfterInternal(colByPredicate: ColumnFilter<*>): ColumnSet<*> { +@PublishedApi +internal inline fun ColumnsResolver<*>.allAfterInternal(crossinline colByPredicate: ColumnFilter<*>): ColumnSet<*> { var take = false return colsInternal { if (take) { @@ -1243,7 +1245,8 @@ internal fun ColumnsResolver<*>.allAfterInternal(colByPredicate: ColumnFilter<*> * @param colByPredicate the predicate used to determine if a column should be included in the resulting set * @return a column set containing all columns that satisfy the predicate */ -internal fun ColumnsResolver<*>.allFromInternal(colByPredicate: ColumnFilter<*>): ColumnSet<*> { +@PublishedApi +internal inline fun ColumnsResolver<*>.allFromInternal(crossinline colByPredicate: ColumnFilter<*>): ColumnSet<*> { var take = false return colsInternal { if (take) { @@ -1261,7 +1264,8 @@ internal fun ColumnsResolver<*>.allFromInternal(colByPredicate: ColumnFilter<*>) * @param colByPredicate the predicate function used to determine if a column should be included in the returned ColumnSet * @return a new ColumnSet containing all columns that come before the first column that satisfies the given predicate */ -internal fun ColumnsResolver<*>.allBeforeInternal(colByPredicate: ColumnFilter<*>): ColumnSet<*> { +@PublishedApi +internal inline fun ColumnsResolver<*>.allBeforeInternal(crossinline colByPredicate: ColumnFilter<*>): ColumnSet<*> { var take = true return colsInternal { if (!take) { @@ -1279,7 +1283,8 @@ internal fun ColumnsResolver<*>.allBeforeInternal(colByPredicate: ColumnFilter<* * @param colByPredicate a predicate function that takes a ColumnWithPath and returns true if the column satisfies the desired condition. * @return a ColumnSet containing all columns up to the first column that satisfies the given predicate. */ -internal fun ColumnsResolver<*>.allUpToInternal(colByPredicate: ColumnFilter<*>): ColumnSet<*> { +@PublishedApi +internal inline fun ColumnsResolver<*>.allUpToInternal(crossinline colByPredicate: ColumnFilter<*>): ColumnSet<*> { var take = true return colsInternal { if (!take) { diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/any.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/any.kt index d8af3cf838..745963dfa1 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/any.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/any.kt @@ -14,6 +14,6 @@ public fun DataColumn.any(predicate: Predicate): Boolean = values.any( // region DataFrame -public fun DataFrame.any(predicate: RowFilter): Boolean = rows().any { predicate(it, it) } +public inline fun DataFrame.any(predicate: RowFilter): Boolean = rows().any { predicate(it, it) } // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/associate.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/associate.kt index 3e6d9fb442..a6dce766ac 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/associate.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/associate.kt @@ -6,10 +6,10 @@ import org.jetbrains.kotlinx.dataframe.RowExpression // region DataFrame -public fun DataFrame.associateBy(transform: RowExpression): Map> = +public inline fun DataFrame.associateBy(transform: RowExpression): Map> = rows().associateBy { transform(it, it) } -public fun DataFrame.associate(transform: RowExpression>): Map = +public inline fun DataFrame.associate(transform: RowExpression>): Map = rows().associate { transform(it, it) } // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colGroups.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colGroups.kt index b86de0d5d4..a36f851d13 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colGroups.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colGroups.kt @@ -178,8 +178,8 @@ public interface ColGroupsColumnsSelectionDsl { * @return A [TransformableColumnSet] containing the column groups that satisfy the filter. */ @Suppress("UNCHECKED_CAST") -internal fun ColumnsResolver<*>.columnGroupsInternal( - filter: (ColumnGroup<*>) -> Boolean, +internal inline fun ColumnsResolver<*>.columnGroupsInternal( + crossinline filter: (ColumnGroup<*>) -> Boolean, ): TransformableColumnSet = colsInternal { it.isColumnGroup() && filter(it) } as TransformableColumnSet // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/cols.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/cols.kt index 5e28c92c67..5deb0f8678 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/cols.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/cols.kt @@ -1108,7 +1108,8 @@ internal fun SingleColumn>.colsInternal(refs: Iterable.colsInternal(predicate: ColumnFilter<*>): TransformableColumnSet<*> = +@PublishedApi +internal inline fun ColumnsResolver<*>.colsInternal(crossinline predicate: ColumnFilter<*>): TransformableColumnSet<*> = allColumnsInternal().transform { it.filter(predicate) } internal fun ColumnsResolver<*>.colsInternal(indices: IntArray): TransformableColumnSet<*> = diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colsOf.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colsOf.kt index 6a574fe1cd..7b5e59787c 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colsOf.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colsOf.kt @@ -264,7 +264,10 @@ public inline fun SingleColumn>.colsOf( * match the given [filter] and are the given [type]. */ @Suppress("UNCHECKED_CAST") -internal fun ColumnsResolver<*>.colsOfInternal(type: KType, filter: ColumnFilter): TransformableColumnSet = +internal inline fun ColumnsResolver<*>.colsOfInternal( + type: KType, + crossinline filter: ColumnFilter, +): TransformableColumnSet = colsInternal { it.isSubtypeOf(type) && filter(it.cast()) } as TransformableColumnSet diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colsOfKind.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colsOfKind.kt index e16eb52d39..4da0c8f58d 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colsOfKind.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colsOfKind.kt @@ -201,9 +201,9 @@ public interface ColsOfKindColumnsSelectionDsl { * @param filter The filter function to apply on each column. Must accept a ColumnWithPath object and return a Boolean. * @return A [TransformableColumnSet] containing the columns of given kinds that satisfy the filter. */ -internal fun ColumnsResolver<*>.columnsOfKindInternal( +internal inline fun ColumnsResolver<*>.columnsOfKindInternal( kinds: Set, - filter: ColumnFilter<*>, + crossinline filter: ColumnFilter<*>, ): TransformableColumnSet<*> = colsInternal { it.kind() in kinds && filter(it) } // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/count.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/count.kt index 6ee9c8820a..aa3e601225 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/count.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/count.kt @@ -25,7 +25,7 @@ public fun DataColumn.count(predicate: Predicate? = null): Int = public fun AnyRow.count(): Int = columnsCount() -public fun AnyRow.count(predicate: Predicate): Int = values().count(predicate) +public inline fun AnyRow.count(predicate: Predicate): Int = values().count(predicate) // endregion @@ -33,7 +33,7 @@ public fun AnyRow.count(predicate: Predicate): Int = values().count(predic public fun DataFrame.count(): Int = rowsCount() -public fun DataFrame.count(predicate: RowFilter): Int = rows().count { predicate(it, it) } +public inline fun DataFrame.count(predicate: RowFilter): Int = rows().count { predicate(it, it) } // endregion @@ -46,8 +46,10 @@ public fun Grouped.count(resultName: String = "count"): DataFrame = @Refine @Interpretable("GroupByCount0") -public fun Grouped.count(resultName: String = "count", predicate: RowFilter): DataFrame = - aggregateValue(resultName) { count(predicate) default 0 } +public inline fun Grouped.count( + resultName: String = "count", + crossinline predicate: RowFilter, +): DataFrame = aggregateValue(resultName) { count(predicate) default 0 } // endregion @@ -55,7 +57,7 @@ public fun Grouped.count(resultName: String = "count", predicate: RowFilt public fun Pivot.count(): DataRow = delegate { count() } -public fun Pivot.count(predicate: RowFilter): DataRow = delegate { count(predicate) } +public inline fun Pivot.count(crossinline predicate: RowFilter): DataRow = delegate { count(predicate) } // endregion @@ -63,6 +65,10 @@ public fun Pivot.count(predicate: RowFilter): DataRow = delegate { public fun PivotGroupBy.count(): DataFrame = aggregate { count() default 0 } -public fun PivotGroupBy.count(predicate: RowFilter): DataFrame = aggregate { count(predicate) default 0 } +public inline fun PivotGroupBy.count(crossinline predicate: RowFilter): DataFrame = + aggregate { + count(predicate) default + 0 + } // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/drop.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/drop.kt index 6babc9217f..ba28f33a86 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/drop.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/drop.kt @@ -24,7 +24,7 @@ import kotlin.reflect.KProperty // region DataColumn -public fun DataColumn.drop(predicate: Predicate): DataColumn = filter { !predicate(it) } +public inline fun DataColumn.drop(predicate: Predicate): DataColumn = filter { !predicate(it) } public fun DataColumn.drop(n: Int): DataColumn = when { @@ -62,13 +62,13 @@ public fun DataFrame.dropLast(n: Int = 1): DataFrame { /** * Returns a DataFrame containing all rows except rows that satisfy the given [predicate]. */ -public fun DataFrame.drop(predicate: RowFilter): DataFrame = filter { !predicate(it, it) } +public inline fun DataFrame.drop(predicate: RowFilter): DataFrame = filter { !predicate(it, it) } /** * Returns a DataFrame containing all rows except first rows that satisfy the given [predicate]. */ -public fun DataFrame.dropWhile(predicate: RowFilter): DataFrame = - firstOrNull { !predicate(it, it) }?.let { drop(it.index) } ?: this +public inline fun DataFrame.dropWhile(predicate: RowFilter): DataFrame = + firstOrNull { !predicate(it, it) }?.let { drop(it.index()) } ?: this // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/duplicate.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/duplicate.kt index 4727b9602e..f88ccb65e5 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/duplicate.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/duplicate.kt @@ -11,7 +11,7 @@ public fun DataFrame.duplicate(n: Int): FrameColumn = List(n) { this } public fun DataFrame.duplicateRows(n: Int): DataFrame = duplicateRowsImpl(n) -public fun DataFrame.duplicateRows(n: Int, filter: RowFilter): DataFrame = +public inline fun DataFrame.duplicateRows(n: Int, filter: RowFilter): DataFrame = duplicateRowsImpl(n, rows().filter { filter(it, it) }.map { it.index() }) public fun DataRow.duplicate(n: Int): DataFrame = duplicateImpl(n) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/filter.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/filter.kt index d25ed5e892..343d0971da 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/filter.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/filter.kt @@ -24,7 +24,7 @@ import kotlin.reflect.KProperty // region DataColumn -public fun DataColumn.filter(predicate: Predicate): DataColumn = +public inline fun DataColumn.filter(predicate: Predicate): DataColumn = indices .filter { predicate(get(it)) } .let { get(it) } @@ -33,8 +33,8 @@ public fun DataColumn.filter(predicate: Predicate): DataColumn = // region DataFrame -public fun DataFrame.filter(predicate: RowFilter): DataFrame = - indices.filter { +public inline fun DataFrame.filter(predicate: RowFilter): DataFrame = + indices().filter { val row = get(it) predicate(row, row) }.let { get(it) } diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/first.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/first.kt index 869f37b275..852eb3d914 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/first.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/first.kt @@ -48,9 +48,15 @@ public fun DataFrame.first(): DataRow { public fun DataFrame.firstOrNull(): DataRow? = if (nrow > 0) first() else null -public fun DataFrame.first(predicate: RowFilter): DataRow = rows().first { predicate(it, it) } +public inline fun DataFrame.first(predicate: RowFilter): DataRow = + rows().first { + predicate(it, it) + } -public fun DataFrame.firstOrNull(predicate: RowFilter): DataRow? = rows().firstOrNull { predicate(it, it) } +public inline fun DataFrame.firstOrNull(predicate: RowFilter): DataRow? = + rows().firstOrNull { + predicate(it, it) + } // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/frameCols.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/frameCols.kt index 1be2a0a5ef..d83d637f9a 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/frameCols.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/frameCols.kt @@ -185,8 +185,8 @@ public interface FrameColsColumnsSelectionDsl { * @return A [TransformableColumnSet] containing the frame columns that satisfy the filter. */ @Suppress("UNCHECKED_CAST") -internal fun ColumnsResolver<*>.frameColumnsInternal( - filter: (FrameColumn<*>) -> Boolean, +internal inline fun ColumnsResolver<*>.frameColumnsInternal( + crossinline filter: (FrameColumn<*>) -> Boolean, ): TransformableColumnSet = colsInternal { it.isFrameColumn() && filter(it.asFrameColumn()) } as TransformableColumnSet diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/group.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/group.kt index a98ba0b6f5..cf2c082039 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/group.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/group.kt @@ -7,17 +7,109 @@ import org.jetbrains.kotlinx.dataframe.DataFrame import org.jetbrains.kotlinx.dataframe.annotations.AccessApiOverload import org.jetbrains.kotlinx.dataframe.annotations.Interpretable import org.jetbrains.kotlinx.dataframe.annotations.Refine +import org.jetbrains.kotlinx.dataframe.columns.ColumnGroup import org.jetbrains.kotlinx.dataframe.columns.ColumnWithPath import org.jetbrains.kotlinx.dataframe.columns.toColumnSet +import org.jetbrains.kotlinx.dataframe.documentation.DocumentationUrls +import org.jetbrains.kotlinx.dataframe.documentation.DslGrammarLink +import org.jetbrains.kotlinx.dataframe.documentation.ExcludeFromSources +import org.jetbrains.kotlinx.dataframe.documentation.Indent +import org.jetbrains.kotlinx.dataframe.documentation.LineBreak +import org.jetbrains.kotlinx.dataframe.documentation.SelectingColumns import org.jetbrains.kotlinx.dataframe.impl.columnName import kotlin.experimental.ExperimentalTypeInference import kotlin.reflect.KProperty // region DataFrame +/** + * Groups the specified [columns\] within the [DataFrame]. + * + * This function does not immediately group the columns but instead select columns to group and + * returns a [GroupClause], + * which serves as an intermediate step. + * The [GroupClause] allows specifying the final + * destination of the selected columns using methods such + * as [into][GroupClause.into] and, + * that return a new [DataFrame] with grouped columns. + * Check out [Grammar]. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * See [Selecting Columns][GroupSelectingOptions]. + * + * For more information: {@include [DocumentationUrls.Group]} + * + * Reverse operation: [ungroup]. + * + * It is a special case of [move] operation. + * + * Don't confuse this with [groupBy], + * which groups the dataframe by the values in the selected columns! + */ +internal interface GroupDocs { + + /** + * {@comment Version of [SelectingColumns] with correctly filled in examples} + * @include [SelectingColumns] {@include [SetGroupOperationArg]} + */ + interface GroupSelectingOptions + + /** + * ## Group Operation Grammar + * {@include [LineBreak]} + * {@include [DslGrammarLink]} + * {@include [LineBreak]} + * + * **[`group`][group]****` { `**`columnsSelector: `[`ColumnsSelector`][ColumnsSelector]**` }`** + * + * {@include [Indent]} + * __`.`__[**`into`**][GroupClause.into]**`(`**`groupName: `[`String`][String]**`)`** + * + * {@include [Indent]} + * __`.`__[**`into`**][GroupClause.into]` { column: `[`ColumnsSelectionDsl`][ColumnsSelectionDsl]`.(`[`ColumnWithPath`][ColumnWithPath]`) -> `[`String`][String]` }` + * + * {@include [Indent]} + * __`.`__[**`into`**][GroupClause.into]` { column: `[`ColumnsSelectionDsl`][ColumnsSelectionDsl]`.(`[`ColumnWithPath`][ColumnWithPath]`) -> `[`AnyColumnReference`][AnyColumnReference]` }` + * + */ + interface Grammar +} + +/** {@set [SelectingColumns.OPERATION] [group][group]} */ +@ExcludeFromSources +private interface SetGroupOperationArg + +/** + * {@include [GroupDocs]} + * ### This Group Overload + */ +@ExcludeFromSources +private interface CommonGroupDocs + +/** + * @include [CommonGroupDocs] + * @include [SelectingColumns.Dsl] {@include [SetGroupOperationArg]} + * ### Examples: + * ```kotlin + * df.group { columnA and columnB }.into("valueCols") + * df.group { colsOf() }.into { it.name.split(".").first() } + * ``` + * @param [columns\] The [Columns Selector][ColumnsSelector] used to select the columns of this [DataFrame] to group. + */ @Interpretable("Group0") public fun DataFrame.group(columns: ColumnsSelector): GroupClause = GroupClause(this, columns) +/** + * @include [CommonGroupDocs] + * @include [SelectingColumns.ColumnNames] {@include [SetGroupOperationArg]} + * ### Example: + * ```kotlin + * df.group("second").into("valueCols") + * df.group("prop.A", "prop.B", "cnt.A", "cnt.B").into { it.name.split(".").first() } + * ``` + * @param [columns\] The [Column Names][String] used to select the columns of this [DataFrame] to group. + */ public fun DataFrame.group(vararg columns: String): GroupClause = group { columns.toColumnSet() } @AccessApiOverload @@ -31,23 +123,112 @@ public fun DataFrame.group(vararg columns: KProperty<*>): GroupClause(internal val df: DataFrame, internal val columns: ColumnsSelector) { override fun toString(): String = "GroupClause(df=$df, columns=$columns)" } // region into +/** + * Groups columns, previously selected with [group], into new or existing column groups + * within the [DataFrame], using an [ColumnsSelectionDsl] expression to specify the target group name for each column. + * The expression is applied to each selected column and determines the name of the column group + * it will be placed into. + * + * If a column group with the specified name does not exist, it will be created. + * + * See [Selecting Columns][SelectingColumns]. + * + * For more information: {@include [DocumentationUrls.Group]} + * + * @include [SelectingColumns.ColumnNames] + * + * ### Example: + * ```kotlin + * // For each selected column, place it under its under a group with its type as name (individual for each column): + * df.group { all() }.into { it.type().toString() } + * ``` + * + * @param column A [ColumnsSelector] expression that takes a column and returns the name of the [ColumnGroup] + * where that column should be grouped. + * All selected columns will be moved under the groups defined by this expression. + */ @JvmName("intoString") @OverloadResolutionByLambdaReturnType @OptIn(ExperimentalTypeInference::class) public fun GroupClause.into(column: ColumnsSelectionDsl.(ColumnWithPath) -> String): DataFrame = df.move(columns).under { column(it).toColumnAccessor() } +/** + * Groups columns, previously selected with [group], into a new or existing column group + * within the [DataFrame] by specifying its path via [ColumnsSelectionDsl] expression. + * + * If the specified path refers to a non-existent column group, it will be created automatically, + * including any missing intermediate segments. + * + * See [Selecting Columns][SelectingColumns]. + * + * For more information: {@include [DocumentationUrls.Group]} + * + * @include [SelectingColumns.ColumnNames] + * + * ### Examples: + * ```kotlin + * // Group selected columns into an existing column group (common for all selected columns): + * df.group("age", "weight").into { info } + * + * // Group selected columns into a nested column group using a path (common for all selected columns) that may contain both existing and new segments: + * df.group { employee.age and employee.weight }.into { pathOf("info", "personal") } + * + * // For each selected column, place it under its ancestor group from two levels up in the column path hierarchy (individual for each column): + * df.group { colsAtAnyDepth().colsOf() }.into { it.path.dropLast(2) } + * ``` + * + * @param column A [ColumnsSelector] expression that takes a column and returns the full path to the [ColumnGroup] + * where that column should be grouped. + * All selected columns will be moved under the groups defined by this expression. + */ @JvmName("intoColumn") public fun GroupClause.into( column: ColumnsSelectionDsl.(ColumnWithPath) -> AnyColumnReference, ): DataFrame = df.move(columns).under(column) +/** + * Groups columns, previously selected with [group], into a new or existing column group + * within the [DataFrame], by specifying its name. + * + * If a column group with the specified name does not exist, it will be created. + * + * See [Selecting Columns][SelectingColumns]. + * + * For more information: {@include [DocumentationUrls.Group]} + * + * @include [SelectingColumns.ColumnNames] + * + * ### Examples: + * ```kotlin + * df.group("age", "weight").into("info") + * df.group { age and weight }.into("info") + * ``` + * + * @param [column] A [ColumnsSelector] that defines the path to a [ColumnGroup] + * in the [DataFrame], where the selected columns will be moved. + */ @Refine @Interpretable("Into0") public fun GroupClause.into(column: String): DataFrame = into(columnGroup().named(column)) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/indices.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/indices.kt index 6edc8c3004..f8ac6c995b 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/indices.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/indices.kt @@ -9,8 +9,8 @@ import org.jetbrains.kotlinx.dataframe.indices public fun AnyFrame.indices(): IntRange = 0 until rowsCount() -public fun DataFrame.indices(filter: RowFilter): List = - indices.filter { +public inline fun DataFrame.indices(filter: RowFilter): List = + indices().filter { val row = get(it) filter(row, row) } diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/last.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/last.kt index b4e6f6de19..e4f425d6c8 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/last.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/last.kt @@ -31,18 +31,21 @@ public fun DataColumn.last(): T = get(size - 1) public fun DataColumn.lastOrNull(): T? = if (size > 0) last() else null -public fun DataColumn.last(predicate: (T) -> Boolean): T = values.last(predicate) +public inline fun DataColumn.last(predicate: (T) -> Boolean): T = values.last(predicate) -public fun DataColumn.lastOrNull(predicate: (T) -> Boolean): T? = values.lastOrNull(predicate) +public inline fun DataColumn.lastOrNull(predicate: (T) -> Boolean): T? = values.lastOrNull(predicate) // endregion // region DataFrame -public fun DataFrame.lastOrNull(predicate: RowFilter): DataRow? = +public inline fun DataFrame.lastOrNull(predicate: RowFilter): DataRow? = rowsReversed().firstOrNull { predicate(it, it) } -public fun DataFrame.last(predicate: RowFilter): DataRow = rowsReversed().first { predicate(it, it) } +public inline fun DataFrame.last(predicate: RowFilter): DataRow = + rowsReversed().first { + predicate(it, it) + } public fun DataFrame.lastOrNull(): DataRow? = if (nrow > 0) get(nrow - 1) else null diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/map.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/map.kt index 98c00fd6c5..fade9f6304 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/map.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/map.kt @@ -36,20 +36,24 @@ public inline fun DataColumn.map(infer: Infer = Infer.Nulls, t return DataColumn.createByType(name(), newValues, typeOf(), infer) } -public fun DataColumn.map(type: KType, infer: Infer = Infer.Nulls, transform: (T) -> R): DataColumn { +public inline fun DataColumn.map( + type: KType, + infer: Infer = Infer.Nulls, + transform: (T) -> R, +): DataColumn { val values = Array(size()) { transform(get(it)) }.asList() return DataColumn.createByType(name(), values, type, infer).cast() } public inline fun DataColumn.mapIndexed( infer: Infer = Infer.Nulls, - crossinline transform: (Int, T) -> R, + transform: (Int, T) -> R, ): DataColumn { val newValues = Array(size()) { transform(it, get(it)) }.asList() return DataColumn.createByType(name(), newValues, typeOf(), infer) } -public fun DataColumn.mapIndexed( +public inline fun DataColumn.mapIndexed( type: KType, infer: Infer = Infer.Nulls, transform: (Int, T) -> R, @@ -62,7 +66,7 @@ public fun DataColumn.mapIndexed( // region DataFrame -public fun DataFrame.map(transform: RowExpression): List = rows().map { transform(it, it) } +public inline fun DataFrame.map(transform: RowExpression): List = rows().map { transform(it, it) } public inline fun ColumnsContainer.mapToColumn( name: String, @@ -109,7 +113,7 @@ public fun ColumnsContainer.mapToColumn( @Refine @Interpretable("MapToFrame") -public fun DataFrame.mapToFrame(body: AddDsl.() -> Unit): AnyFrame { +public inline fun DataFrame.mapToFrame(body: AddDsl.() -> Unit): AnyFrame { val dsl = AddDsl(this) body(dsl) return dataFrameOf(dsl.columns) @@ -119,7 +123,7 @@ public fun DataFrame.mapToFrame(body: AddDsl.() -> Unit): AnyFrame { // region GroupBy -public fun GroupBy.map(body: Selector, R>): List = +public inline fun GroupBy.map(body: Selector, R>): List = keys.rows().mapIndexedNotNull { index, row -> val group = groups[index] val g = GroupWithKey(row, group) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/single.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/single.kt index b25a0f6b93..e30a59ad24 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/single.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/single.kt @@ -41,10 +41,10 @@ public fun DataFrame.single(): DataRow = public fun DataFrame.singleOrNull(): DataRow? = rows().singleOrNull() -public fun DataFrame.single(predicate: RowExpression): DataRow = +public inline fun DataFrame.single(predicate: RowExpression): DataRow = rows().single { predicate(it, it) } -public fun DataFrame.singleOrNull(predicate: RowExpression): DataRow? = +public inline fun DataFrame.singleOrNull(predicate: RowExpression): DataRow? = rows().singleOrNull { predicate(it, it) } // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/split.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/split.kt index bf56a687f7..5dc225b430 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/split.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/split.kt @@ -32,7 +32,12 @@ public fun DataFrame.split(vararg columns: ColumnReference): Split @AccessApiOverload public fun DataFrame.split(vararg columns: KProperty): Split = split { columns.toColumnSet() } -public class Split(internal val df: DataFrame, internal val columns: ColumnsSelector) { +public class Split( + @PublishedApi + internal val df: DataFrame, + @PublishedApi + internal val columns: ColumnsSelector, +) { public fun

cast(): Split = this as Split override fun toString(): String = "Split(df=$df, columns=$columns)" @@ -103,9 +108,9 @@ public fun Split.by( } @PublishedApi -internal fun Split.by( +internal inline fun Split.by( type: KType, - splitter: DataRow.(C) -> Iterable, + crossinline splitter: DataRow.(C) -> Iterable, ): SplitWithTransform = SplitWithTransform(df, columns, false, type) { if (it == null) emptyList() else splitter(it).asList() @@ -274,8 +279,10 @@ public inline fun , reified R> Split.intoRows(dropEmpty public fun Split.intoRows(dropEmpty: Boolean = true): DataFrame = by { it.rows() }.intoRows(dropEmpty) -internal fun Convert.splitInplace(type: KType, transform: DataRow.(C) -> Iterable) = - withRowCellImpl(getListType(type), Infer.None) { if (it == null) emptyList() else transform(it).asList() } +internal inline fun Convert.splitInplace( + type: KType, + crossinline transform: DataRow.(C) -> Iterable, +) = withRowCellImpl(getListType(type), Infer.None) { if (it == null) emptyList() else transform(it).asList() } public fun SplitWithTransform.intoRows(dropEmpty: Boolean = true): DataFrame { val paths = df.getColumnPaths(columns).toColumnSet() diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/take.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/take.kt index 9d5bd27119..40c632718b 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/take.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/take.kt @@ -60,8 +60,8 @@ public fun DataFrame.takeLast(n: Int = 1): DataFrame { /** * Returns a DataFrame containing first rows that satisfy the given [predicate]. */ -public fun DataFrame.takeWhile(predicate: RowFilter): DataFrame = - firstOrNull { !predicate(it, it) }?.let { take(it.index) } ?: this +public inline fun DataFrame.takeWhile(predicate: RowFilter): DataFrame = + firstOrNull { !predicate(it, it) }?.let { take(it.index()) } ?: this // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ungroup.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ungroup.kt index 6ef82d3e33..735930731d 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ungroup.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ungroup.kt @@ -6,19 +6,67 @@ import org.jetbrains.kotlinx.dataframe.DataFrame import org.jetbrains.kotlinx.dataframe.annotations.AccessApiOverload import org.jetbrains.kotlinx.dataframe.annotations.Interpretable import org.jetbrains.kotlinx.dataframe.annotations.Refine +import org.jetbrains.kotlinx.dataframe.columns.ColumnGroup import org.jetbrains.kotlinx.dataframe.columns.toColumnSet +import org.jetbrains.kotlinx.dataframe.documentation.DocumentationUrls +import org.jetbrains.kotlinx.dataframe.documentation.ExcludeFromSources +import org.jetbrains.kotlinx.dataframe.documentation.SelectingColumns import org.jetbrains.kotlinx.dataframe.impl.columns.toColumnSet import org.jetbrains.kotlinx.dataframe.impl.removeAt import kotlin.reflect.KProperty // region DataFrame +/** + * Ungroups the specified [column groups][columns\] within the [DataFrame], i.e., + * replaces each [ColumnGroup] with its nested columns. + * + * See [Selecting Columns][UngroupSelectingOptions]. + * + * For more information: {@include [DocumentationUrls.Ungroup]} + * + * Reverse operation: [group]. + */ +internal interface UngroupDocs { + /** + * {@comment Version of [SelectingColumns] with correctly filled in examples} + * @include [SelectingColumns] {@include [SetUngroupOperationArg]} + */ + interface UngroupSelectingOptions +} + +/** {@set [SelectingColumns.OPERATION] [ungroup][ungroup]} */ +@ExcludeFromSources +private interface SetUngroupOperationArg + +/** + * {@include [UngroupDocs]} + * ### This Ungroup Overload + */ +@ExcludeFromSources +private interface CommonUngroupDocs + +/** + * @include [CommonUngroupDocs] + * @include [SelectingColumns.Dsl] {@include [SetUngroupOperationArg]} + * ### Examples: + * ```kotlin + * df.ungroup { groupA and groupB } + * df.ungroup { all() } + * ``` + * @param [columns\] The [Columns Selector][ColumnsSelector] used to select the column groups of this [DataFrame] to ungroup. + */ @Refine @Interpretable("Ungroup0") public fun DataFrame.ungroup(columns: ColumnsSelector): DataFrame = move { columns.toColumnSet().colsInGroups() } .into { it.path.removeAt(it.path.size - 2).toPath() } +/** + * @include [CommonUngroupDocs] + * @include [SelectingColumns.ColumnNames.WithExample] {@include [SetUngroupOperationArg]} + * @param [columns\] The [Column Names][String] used to select the columns of this [DataFrame] to ungroup. + */ public fun DataFrame.ungroup(vararg columns: String): DataFrame = ungroup { columns.toColumnSet() } @AccessApiOverload diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/update.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/update.kt index 407cf27060..4563b7728e 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/update.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/update.kt @@ -259,7 +259,7 @@ public fun Update.at(rowRange: IntRange): Update = where { in * - {@include [SeeAlsoPerCol]} * @param [expression] The {@include [ExpressionsGivenRowAndColumn.RowColumnExpressionLink]} to provide a new value for every selected cell giving its row and column. */ -public fun Update.perRowCol(expression: RowColumnExpression): DataFrame = +public inline fun Update.perRowCol(crossinline expression: RowColumnExpression): DataFrame = updateImpl { row, column, _ -> expression(row, column) } /** [Update per row col][Update.perRowCol] to provide a new value for every selected cell giving its row and column. */ @@ -286,7 +286,7 @@ public typealias UpdateExpression = AddDataRow.(C) -> R */ @Refine @Interpretable("UpdateWith0") -public fun Update.with(expression: UpdateExpression): DataFrame = +public inline fun Update.with(crossinline expression: UpdateExpression): DataFrame = updateImpl { row, _, value -> expression(row, value) } diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/valueCols.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/valueCols.kt index ca386fdf71..8f35d368ac 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/valueCols.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/valueCols.kt @@ -181,7 +181,8 @@ public interface ValueColsColumnsSelectionDsl { * @param filter The filter function to apply on each value column. Must accept a ValueColumn object and return a Boolean. * @return A [TransformableColumnSet] containing the value columns that satisfy the filter. */ -internal fun ColumnsResolver<*>.valueColumnsInternal(filter: (ValueColumn<*>) -> Boolean): TransformableColumnSet<*> = - colsInternal { it.isValueColumn() && filter(it) } +internal inline fun ColumnsResolver<*>.valueColumnsInternal( + crossinline filter: (ValueColumn<*>) -> Boolean, +): TransformableColumnSet<*> = colsInternal { it.isValueColumn() && filter(it) } // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/columns/BaseColumn.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/columns/BaseColumn.kt index 9117e01bf8..3e8336f8d4 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/columns/BaseColumn.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/columns/BaseColumn.kt @@ -97,6 +97,7 @@ public interface BaseColumn : ColumnReference { (this as DataColumnInternal<*>).rename(property.columnName).forceResolve() as BaseColumn } +@PublishedApi internal val BaseColumn.values: Iterable get() = values() internal val AnyBaseCol.size: Int get() = size() diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt index 3047a30697..f4dab96c72 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt @@ -92,4 +92,10 @@ internal interface DocumentationUrls { /** [See `move` on the documentation website.]({@include [Url]}/move.html) */ interface Move + + /** [See `group` on the documentation website.]({@include [Url]}/group.html) */ + interface Group + + /** [See `group` on the documentation website.]({@include [Url]}/ungroup.html) */ + interface Ungroup } diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/duplicate.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/duplicate.kt index 159c02ca3a..db4dec61cd 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/duplicate.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/duplicate.kt @@ -72,6 +72,7 @@ internal fun DataColumn.duplicateValuesImpl(n: Int, indicesSorted: Iterab } }.cast() +@PublishedApi internal fun DataFrame.duplicateRowsImpl(n: Int, indicesSorted: Iterable): DataFrame = columns() .map { it.duplicateValuesImpl(n, indicesSorted) } diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/format.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/format.kt index 07e6f68039..a1c0fce0c3 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/format.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/format.kt @@ -48,7 +48,9 @@ internal fun linearGradient( } } -internal fun FormatClause.formatImpl(formatter: RowColFormatter): FormattedFrame { +internal inline fun FormatClause.formatImpl( + crossinline formatter: RowColFormatter, +): FormattedFrame { val columns = if (columns != null) { df.getColumnsWithPaths(columns) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/groupBy.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/groupBy.kt index beba1b686d..6902b9a795 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/groupBy.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/groupBy.kt @@ -21,6 +21,7 @@ internal class GroupedDataRowImpl(private val row: DataRow, private val override fun group() = frameCol[row.index()] } +@PublishedApi internal fun DataFrame.groupByImpl(moveToTop: Boolean, columns: ColumnsSelector): GroupBy { val nameGenerator = nameGenerator(GroupBy.groupedColumnAccessor.name()) var keyColumns = getColumnsWithPaths(columns) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/Utils.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/Utils.kt index 50b1587641..3001085373 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/Utils.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/Utils.kt @@ -189,8 +189,9 @@ internal fun SingleColumn.transformSingle( * or it can be used as a [TransformableColumnSet]<[B]>, where a [ColumnsResolverTransformer] can be injected before * the [converter] is applied. */ -internal fun ColumnsResolver.transform( - converter: (List>) -> List>, +@PublishedApi +internal inline fun ColumnsResolver.transform( + crossinline converter: (List>) -> List>, ): TransformableColumnSet = object : TransformableColumnSet { override fun resolve(context: ColumnResolutionContext) = diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/constructors.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/constructors.kt index 84a6368b8e..3f225e76d1 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/constructors.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/constructors.kt @@ -115,8 +115,8 @@ internal fun computeValues(df: DataFrame, expression: AddExpression createColumnSet( - resolver: (context: ColumnResolutionContext) -> List>, +internal inline fun createColumnSet( + crossinline resolver: (context: ColumnResolutionContext) -> List>, ): ColumnSet = object : ColumnSet { override fun resolve(context: ColumnResolutionContext) = resolver(context) @@ -142,8 +142,8 @@ internal fun createTransformableColumnSet( // region DSL -internal fun , C> Selector>.toColumnSet( - createReceiver: (ColumnResolutionContext) -> T, +internal inline fun , C> Selector>.toColumnSet( + crossinline createReceiver: (ColumnResolutionContext) -> T, ): ColumnSet = createColumnSet { val receiver = createReceiver(it)