From 5ced6a0b876554274fdac797e95b0bccd3616580 Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Wed, 26 Mar 2025 16:45:36 +0400 Subject: [PATCH 1/6] inline functions --- .../dataframe/api/ColumnReferenceApi.kt | 1 + .../jetbrains/kotlinx/dataframe/api/add.kt | 3 ++- .../jetbrains/kotlinx/dataframe/api/all.kt | 13 +++++++--- .../jetbrains/kotlinx/dataframe/api/cols.kt | 3 ++- .../jetbrains/kotlinx/dataframe/api/count.kt | 4 +-- .../jetbrains/kotlinx/dataframe/api/filter.kt | 4 +-- .../jetbrains/kotlinx/dataframe/api/first.kt | 8 +++--- .../jetbrains/kotlinx/dataframe/api/format.kt | 14 +++++----- .../kotlinx/dataframe/api/groupBy.kt | 8 +++--- .../jetbrains/kotlinx/dataframe/api/last.kt | 8 +++--- .../jetbrains/kotlinx/dataframe/api/map.kt | 26 ++++++++++++------- .../jetbrains/kotlinx/dataframe/api/max.kt | 12 ++++----- .../jetbrains/kotlinx/dataframe/api/min.kt | 8 +++--- .../jetbrains/kotlinx/dataframe/api/select.kt | 6 ++--- .../jetbrains/kotlinx/dataframe/api/sort.kt | 4 +-- .../jetbrains/kotlinx/dataframe/api/take.kt | 2 +- .../jetbrains/kotlinx/dataframe/api/update.kt | 2 +- .../kotlinx/dataframe/impl/columns/Utils.kt | 5 ++-- 18 files changed, 74 insertions(+), 57 deletions(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ColumnReferenceApi.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ColumnReferenceApi.kt index 40c90f36d3..ef3926567c 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ColumnReferenceApi.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ColumnReferenceApi.kt @@ -6,6 +6,7 @@ import org.jetbrains.kotlinx.dataframe.columns.ValueColumn import org.jetbrains.kotlinx.dataframe.impl.asList import kotlin.reflect.typeOf +@PublishedApi internal val ColumnReference<*>.name: String get() = name() public inline fun ColumnReference.withValues(vararg values: T): ValueColumn = 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 db21bfd7da..5e9fedfa3e 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 @@ -51,7 +51,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(crossinline predicate: RowFilter): Boolean = rows().all { predicate(it, it) } // endregion @@ -1182,6 +1182,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) { @@ -1203,7 +1204,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) { @@ -1221,7 +1223,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) { @@ -1239,6 +1242,7 @@ 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 */ +@PublishedApi internal fun ColumnsResolver<*>.allBeforeInternal(colByPredicate: ColumnFilter<*>): ColumnSet<*> { var take = true return colsInternal { @@ -1257,7 +1261,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/cols.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/cols.kt index 32d9d5b1ea..35d67a740e 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 @@ -1105,7 +1105,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/count.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/count.kt index 6ee9c8820a..0242ae2606 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 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..110b63c089 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,7 +33,7 @@ public fun DataColumn.filter(predicate: Predicate): DataColumn = // region DataFrame -public fun DataFrame.filter(predicate: RowFilter): DataFrame = +public inline fun DataFrame.filter(predicate: RowFilter): DataFrame = indices.filter { val row = get(it) predicate(row, row) 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..a37a18946e 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 @@ -31,9 +31,9 @@ public fun DataColumn.first(): T = get(0) public fun DataColumn.firstOrNull(): T? = if (size > 0) first() else null -public fun DataColumn.first(predicate: (T) -> Boolean): T = values.first(predicate) +public inline fun DataColumn.first(predicate: (T) -> Boolean): T = values.first(predicate) -public fun DataColumn.firstOrNull(predicate: (T) -> Boolean): T? = values.firstOrNull(predicate) +public inline fun DataColumn.firstOrNull(predicate: (T) -> Boolean): T? = values.firstOrNull(predicate) // endregion @@ -48,9 +48,9 @@ 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/format.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/format.kt index c0813d101d..b7ed1ead61 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/format.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/format.kt @@ -23,29 +23,29 @@ import kotlin.reflect.KProperty // region format -public fun DataFrame.format(columns: ColumnsSelector): FormatClause = FormatClause(this, columns) +public inline fun DataFrame.format(noinline columns: ColumnsSelector): FormatClause = FormatClause(this, columns) -public fun DataFrame.format(vararg columns: String): FormatClause = format { columns.toColumnSet() } +public inline fun DataFrame.format(vararg columns: String): FormatClause = format { columns.toColumnSet() } @AccessApiOverload -public fun DataFrame.format(vararg columns: ColumnReference): FormatClause = +public inline fun DataFrame.format(vararg columns: ColumnReference): FormatClause = format { columns.toColumnSet() } @AccessApiOverload -public fun DataFrame.format(vararg columns: KProperty): FormatClause = +public inline fun DataFrame.format(vararg columns: KProperty): FormatClause = format { columns.toColumnSet() } public fun DataFrame.format(): FormatClause = FormatClause(this) // endregion -public fun FormatClause.perRowCol(formatter: RowColFormatter): FormattedFrame = +public inline fun FormatClause.perRowCol(noinline formatter: RowColFormatter): FormattedFrame = formatImpl(formatter) -public fun FormatClause.with(formatter: CellFormatter): FormattedFrame = +public inline fun FormatClause.with(noinline formatter: CellFormatter): FormattedFrame = formatImpl { row, col -> formatter(row[col]) } -public fun FormatClause.where(filter: RowValueFilter): FormatClause = +public inline fun FormatClause.where(noinline filter: RowValueFilter): FormatClause = FormatClause(filter = filter, df = df, columns = columns, oldFormatter = oldFormatter) public fun FormattedFrame.format(): FormatClause = FormatClause(df, null, formatter) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/groupBy.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/groupBy.kt index eb5be20565..3ad657f90a 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/groupBy.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/groupBy.kt @@ -31,16 +31,16 @@ import kotlin.reflect.KProperty */ @Refine @Interpretable("DataFrameGroupBy") -public fun DataFrame.groupBy(moveToTop: Boolean = true, cols: ColumnsSelector): GroupBy = +public inline fun DataFrame.groupBy(moveToTop: Boolean = true, cols: ColumnsSelector): GroupBy = groupByImpl(moveToTop, cols) @AccessApiOverload -public fun DataFrame.groupBy(vararg cols: KProperty<*>): GroupBy = groupBy { cols.toColumnSet() } +public inline fun DataFrame.groupBy(vararg cols: KProperty<*>): GroupBy = groupBy { cols.toColumnSet() } -public fun DataFrame.groupBy(vararg cols: String): GroupBy = groupBy { cols.toColumnSet() } +public inline fun DataFrame.groupBy(vararg cols: String): GroupBy = groupBy { cols.toColumnSet() } @AccessApiOverload -public fun DataFrame.groupBy(vararg cols: AnyColumnReference, moveToTop: Boolean = true): GroupBy = +public inline fun DataFrame.groupBy(vararg cols: AnyColumnReference, moveToTop: Boolean = true): GroupBy = groupBy(moveToTop) { cols.toColumnSet() } // endregion 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..32e4e8f78d 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,18 @@ 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..dc12f5fd5d 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 @@ -31,12 +31,19 @@ public inline fun ColumnReference.map( // region DataColumn -public inline fun DataColumn.map(infer: Infer = Infer.Nulls, transform: (T) -> R): DataColumn { +public inline fun DataColumn.map( + infer: Infer = Infer.Nulls, + crossinline transform: (T) -> R +): DataColumn { val newValues = Array(size()) { transform(get(it)) }.asList() 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, + crossinline transform: (T) -> R +): DataColumn { val values = Array(size()) { transform(get(it)) }.asList() return DataColumn.createByType(name(), values, type, infer).cast() } @@ -49,10 +56,10 @@ public inline fun DataColumn.mapIndexed( 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, + crossinline transform: (Int, T) -> R, ): DataColumn { val values = Array(size()) { transform(it, get(it)) }.asList() return DataColumn.createByType(name(), values, type, infer).cast() @@ -62,7 +69,8 @@ public fun DataColumn.mapIndexed( // region DataFrame -public fun DataFrame.map(transform: RowExpression): List = rows().map { transform(it, it) } +public inline fun DataFrame.map(crossinline transform: RowExpression): List = + rows().map { transform(it, it) } public inline fun ColumnsContainer.mapToColumn( name: String, @@ -109,7 +117,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,17 +127,17 @@ public fun DataFrame.mapToFrame(body: AddDsl.() -> Unit): AnyFrame { // region GroupBy -public fun GroupBy.map(body: Selector, R>): List = +public inline fun GroupBy.map(crossinline body: Selector, R>): List = keys.rows().mapIndexedNotNull { index, row -> val group = groups[index] val g = GroupWithKey(row, group) body(g, g) } -public fun GroupBy.mapToRows(body: Selector, DataRow?>): DataFrame = +public inline fun GroupBy.mapToRows(crossinline body: Selector, DataRow?>): DataFrame = map(body).concat() -public fun GroupBy.mapToFrames(body: Selector, DataFrame>): FrameColumn = +public inline fun GroupBy.mapToFrames(noinline body: Selector, DataFrame>): FrameColumn = DataColumn.createFrameColumn(groups.name, map(body)) // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/max.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/max.kt index 6de276a7e4..6b194cdba7 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/max.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/max.kt @@ -29,15 +29,15 @@ public fun > DataColumn.max(): T = maxOrNull().suggestIfNu public fun > DataColumn.maxOrNull(): T? = asSequence().filterNotNull().maxOrNull() -public fun > DataColumn.maxBy(selector: (T) -> R): T = +public inline fun > DataColumn.maxBy(selector: (T) -> R): T = maxByOrNull(selector).suggestIfNull("maxBy") -public fun > DataColumn.maxByOrNull(selector: (T) -> R): T? = values.maxByOrNull(selector) +public inline fun > DataColumn.maxByOrNull(selector: (T) -> R): T? = values.maxByOrNull(selector) -public fun > DataColumn.maxOf(selector: (T) -> R): R = +public inline fun > DataColumn.maxOf(selector: (T) -> R): R = maxOfOrNull(selector).suggestIfNull("maxOf") -public fun > DataColumn.maxOfOrNull(selector: (T) -> R): R? = values.maxOfOrNull(selector) +public inline fun > DataColumn.maxOfOrNull(selector: (T) -> R): R? = values.maxOfOrNull(selector) // endregion @@ -97,10 +97,10 @@ public fun > DataFrame.maxOrNull(vararg columns: ColumnR public fun > DataFrame.maxOrNull(vararg columns: KProperty): C? = maxOrNull { columns.toColumnSet() } -public fun > DataFrame.maxOf(expression: RowExpression): C = +public inline fun > DataFrame.maxOf(expression: RowExpression): C = maxOfOrNull(expression).suggestIfNull("maxOf") -public fun > DataFrame.maxOfOrNull(expression: RowExpression): C? = +public inline fun > DataFrame.maxOfOrNull(expression: RowExpression): C? = rows().maxOfOrNull { expression(it, it) } public fun > DataFrame.maxBy(expression: RowExpression): DataRow = diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/min.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/min.kt index c843cc871f..8b0b971669 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/min.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/min.kt @@ -29,15 +29,15 @@ public fun > DataColumn.min(): T = minOrNull().suggestIfNu public fun > DataColumn.minOrNull(): T? = asSequence().filterNotNull().minOrNull() -public fun > DataColumn.minBy(selector: (T) -> R): T = +public inline fun > DataColumn.minBy(selector: (T) -> R): T = minByOrNull(selector).suggestIfNull("minBy") -public fun > DataColumn.minByOrNull(selector: (T) -> R): T? = values.minByOrNull(selector) +public inline fun > DataColumn.minByOrNull(selector: (T) -> R): T? = values.minByOrNull(selector) -public fun > DataColumn.minOf(selector: (T) -> R): R = +public inline fun > DataColumn.minOf(selector: (T) -> R): R = minOfOrNull(selector).suggestIfNull("minOf") -public fun > DataColumn.minOfOrNull(selector: (T) -> R): R? = values.minOfOrNull(selector) +public inline fun > DataColumn.minOfOrNull(selector: (T) -> R): R? = values.minOfOrNull(selector) // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt index 59295da93c..889d39879e 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt @@ -64,7 +64,7 @@ private interface CommonSelectDocs */ @Refine @Interpretable("Select0") -public fun DataFrame.select(columns: ColumnsSelector): DataFrame = get(columns).toDataFrame().cast() +public inline fun DataFrame.select(noinline columns: ColumnsSelector): DataFrame = get(columns).toDataFrame().cast() /** * @include [CommonSelectDocs] @@ -72,14 +72,14 @@ public fun DataFrame.select(columns: ColumnsSelector): DataFrame * @param [columns] The [KProperties][KProperty] used to select the columns of this [DataFrame]. */ @AccessApiOverload -public fun DataFrame.select(vararg columns: KProperty<*>): DataFrame = select { columns.toColumnSet() } +public inline fun DataFrame.select(vararg columns: KProperty<*>): DataFrame = select { columns.toColumnSet() } /** * @include [CommonSelectDocs] * @include [SelectingColumns.ColumnNames.WithExample] {@include [SetSelectOperationArg]} * @param [columns] The [Column Names][String] used to select the columns of this [DataFrame]. */ -public fun DataFrame.select(vararg columns: String): DataFrame = select { columns.toColumnSet() } +public inline fun DataFrame.select(vararg columns: String): DataFrame = select { columns.toColumnSet() } /** * @include [CommonSelectDocs] diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/sort.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/sort.kt index c8b6579e70..36a2b048c3 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/sort.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/sort.kt @@ -100,7 +100,7 @@ public fun > C.sortWith(comparator: Comparator): C = DataColumn.createByType(name, values().sortedWith(comparator), type) as C /** @include [CommonDataColumnSortWithDocs] */ -public fun > C.sortWith(comparator: (T, T) -> Int): C = sortWith(Comparator(comparator)) +public inline fun > C.sortWith(noinline comparator: (T, T) -> Int): C = sortWith(Comparator(comparator)) // endregion @@ -122,7 +122,7 @@ public fun DataFrame.sortWith(comparator: Comparator>): DataFr return this[permutation] } -public fun DataFrame.sortWith(comparator: (DataRow, DataRow) -> Int): DataFrame = +public inline fun DataFrame.sortWith(noinline comparator: (DataRow, DataRow) -> Int): DataFrame = sortWith(Comparator(comparator)) public fun DataFrame.sortByDesc(columns: SortColumnsSelector): DataFrame { 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..52c3594fa4 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,7 +60,7 @@ 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 = +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/update.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/update.kt index 407cf27060..230087a22e 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 @@ -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(noinline expression: UpdateExpression): DataFrame = updateImpl { row, _, value -> expression(row, value) } 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) = From 2472d17141f6241d2859504395a414eac45abca5 Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Thu, 27 Mar 2025 16:53:50 +0400 Subject: [PATCH 2/6] inline functions --- core/api/core.api | 32 +++++++++++++++++++ .../jetbrains/kotlinx/dataframe/DataFrame.kt | 2 ++ .../jetbrains/kotlinx/dataframe/DataRow.kt | 2 ++ .../dataframe/api/ColumnReferenceApi.kt | 1 - .../kotlinx/dataframe/api/DataRowApi.kt | 21 ++++++------ .../jetbrains/kotlinx/dataframe/api/any.kt | 2 +- .../kotlinx/dataframe/api/associate.kt | 4 +-- .../kotlinx/dataframe/api/colGroups.kt | 4 +-- .../jetbrains/kotlinx/dataframe/api/colsOf.kt | 5 ++- .../kotlinx/dataframe/api/colsOfKind.kt | 4 +-- .../jetbrains/kotlinx/dataframe/api/count.kt | 18 +++++++---- .../jetbrains/kotlinx/dataframe/api/drop.kt | 7 ++-- .../kotlinx/dataframe/api/duplicate.kt | 2 +- .../jetbrains/kotlinx/dataframe/api/filter.kt | 4 +-- .../jetbrains/kotlinx/dataframe/api/first.kt | 14 +++++--- .../jetbrains/kotlinx/dataframe/api/format.kt | 14 ++++---- .../kotlinx/dataframe/api/frameCols.kt | 4 +-- .../kotlinx/dataframe/api/groupBy.kt | 8 ++--- .../kotlinx/dataframe/api/indices.kt | 2 +- .../jetbrains/kotlinx/dataframe/api/last.kt | 7 ++-- .../jetbrains/kotlinx/dataframe/api/map.kt | 8 ++--- .../jetbrains/kotlinx/dataframe/api/max.kt | 15 +++++---- .../jetbrains/kotlinx/dataframe/api/min.kt | 6 ++-- .../jetbrains/kotlinx/dataframe/api/select.kt | 3 +- .../jetbrains/kotlinx/dataframe/api/single.kt | 4 +-- .../jetbrains/kotlinx/dataframe/api/sort.kt | 4 +-- .../jetbrains/kotlinx/dataframe/api/split.kt | 17 +++++++--- .../jetbrains/kotlinx/dataframe/api/take.kt | 2 +- .../jetbrains/kotlinx/dataframe/api/update.kt | 4 +-- .../kotlinx/dataframe/api/valueCols.kt | 5 +-- .../kotlinx/dataframe/columns/BaseColumn.kt | 1 + .../jetbrains/kotlinx/dataframe/impl/Utils.kt | 1 + .../kotlinx/dataframe/impl/api/describe.kt | 7 ++-- .../kotlinx/dataframe/impl/api/duplicate.kt | 1 + .../kotlinx/dataframe/impl/api/format.kt | 4 ++- .../kotlinx/dataframe/impl/api/groupBy.kt | 1 + .../kotlinx/dataframe/impl/api/joinWith.kt | 2 +- .../dataframe/impl/columns/constructors.kt | 8 ++--- 38 files changed, 163 insertions(+), 87 deletions(-) diff --git a/core/api/core.api b/core/api/core.api index f03122f4c3..fb7793d5d5 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -104,6 +104,7 @@ public final class org/jetbrains/kotlinx/dataframe/DataFrameKt { public static final fun get (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public static final fun get (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/ranges/ClosedRange;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; public static final fun get (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;[Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; + public static final fun getIndices (Lorg/jetbrains/kotlinx/dataframe/DataFrame;)Lkotlin/ranges/IntRange; public static final fun size (Lorg/jetbrains/kotlinx/dataframe/DataFrame;)Lorg/jetbrains/kotlinx/dataframe/impl/DataFrameSize; } @@ -163,6 +164,10 @@ public final class org/jetbrains/kotlinx/dataframe/DataRow$Companion { public final fun getEmpty ()Lorg/jetbrains/kotlinx/dataframe/DataRow; } +public final class org/jetbrains/kotlinx/dataframe/DataRowKt { + public static final fun getIndex (Lorg/jetbrains/kotlinx/dataframe/DataRow;)I +} + public abstract interface class org/jetbrains/kotlinx/dataframe/aggregation/Aggregatable { } @@ -314,6 +319,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; @@ -592,8 +598,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 { @@ -1023,6 +1035,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; @@ -3678,6 +3694,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; } @@ -4568,6 +4586,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; @@ -5149,6 +5171,7 @@ public final class org/jetbrains/kotlinx/dataframe/impl/UtilsKt { public static final fun headPlusArray (J[J)[J public static final fun headPlusArray (S[S)[S public static final fun headPlusArray (Z[Z)[Z + public static final fun indexOfMax (Lkotlin/sequences/Sequence;)I public static final fun toCamelCaseByDelimiters (Ljava/lang/String;Lkotlin/text/Regex;Ljava/lang/String;)Ljava/lang/String; public static synthetic fun toCamelCaseByDelimiters$default (Ljava/lang/String;Lkotlin/text/Regex;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String; public static final fun zero (Lkotlin/reflect/KClass;)Ljava/lang/Number; @@ -5262,6 +5285,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; } @@ -5380,6 +5411,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/DataFrame.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataFrame.kt index e4825537f8..fc241733ae 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataFrame.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataFrame.kt @@ -135,6 +135,8 @@ public operator fun DataFrame.get(columnRange: ClosedRange): Data internal val ColumnsContainer<*>.ncol get() = columnsCount() internal val AnyFrame.nrow get() = rowsCount() + +@PublishedApi internal val AnyFrame.indices get() = indices() internal val AnyFrame.size: DataFrameSize get() = size() diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataRow.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataRow.kt index 8be75df4e3..a338622972 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataRow.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataRow.kt @@ -149,6 +149,8 @@ public interface DataRow { } internal val AnyRow.values: List get() = values() + +@PublishedApi internal val AnyRow.index: Int get() = index() internal val DataRow.prev: DataRow? get() = this.prev() internal val DataRow.next: DataRow? get() = this.next() diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ColumnReferenceApi.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ColumnReferenceApi.kt index ef3926567c..40c90f36d3 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ColumnReferenceApi.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/ColumnReferenceApi.kt @@ -6,7 +6,6 @@ import org.jetbrains.kotlinx.dataframe.columns.ValueColumn import org.jetbrains.kotlinx.dataframe.impl.asList import kotlin.reflect.typeOf -@PublishedApi internal val ColumnReference<*>.name: String get() = name() public inline fun ColumnReference.withValues(vararg values: T): ValueColumn = 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..5804dc26fd 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,10 @@ internal interface DiffOrNullDocs */ @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType -public fun DataRow.diff(firstRowResult: Double, expression: RowExpression): Double = +public inline fun DataRow.diff( + firstRowResult: Double, + crossinline expression: RowExpression, +): Double = prev()?.let { p -> expression(this, this) - expression(p, p) } ?: firstRowResult @@ -121,21 +124,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, crossinline 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, crossinline 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, crossinline expression: RowExpression): Float = prev()?.let { p -> expression(this, this) - expression(p, p) } ?: firstRowResult @@ -144,25 +147,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(crossinline 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(crossinline 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(crossinline 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(crossinline expression: RowExpression): Float? = prev()?.let { p -> expression(this, this) - expression(p, p) } public fun AnyRow.columnsCount(): Int = df().ncol @@ -205,7 +208,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, crossinline expression: RowExpression): Double { var count = 0 return backwardIterable().take(k).sumOf { count++ 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..3bb56f3bac 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(crossinline 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..475b5926e6 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(crossinline transform: RowExpression): Map> = rows().associateBy { transform(it, it) } -public fun DataFrame.associate(transform: RowExpression>): Map = +public inline fun DataFrame.associate(crossinline 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/colsOf.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colsOf.kt index 886d66bd02..0168055b5d 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 @@ -262,7 +262,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 8aada393eb..d11bf3f344 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 @@ -199,9 +199,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 0242ae2606..50920ca041 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 inline fun AnyRow.count(predicate: Predicate): Int = values().count(predicate) +public inline fun AnyRow.count(crossinline predicate: Predicate): Int = values().count(predicate) // endregion @@ -33,7 +33,7 @@ public inline fun AnyRow.count(predicate: Predicate): Int = values().count public fun DataFrame.count(): Int = rowsCount() -public inline fun DataFrame.count(predicate: RowFilter): Int = rows().count { predicate(it, it) } +public inline fun DataFrame.count(crossinline 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 4062b45d2a..bc227b113a 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 @@ -23,7 +23,7 @@ import kotlin.reflect.KProperty // region DataColumn -public fun DataColumn.drop(predicate: Predicate): DataColumn = filter { !predicate(it) } +public inline fun DataColumn.drop(crossinline predicate: Predicate): DataColumn = filter { !predicate(it) } public fun DataColumn.drop(n: Int): DataColumn = when { @@ -61,12 +61,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(crossinline 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 = +public inline fun DataFrame.dropWhile(crossinline 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..e7db27d8f1 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, crossinline 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 110b63c089..d352f1475f 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 inline fun DataColumn.filter(predicate: Predicate): DataColumn = +public inline fun DataColumn.filter(crossinline predicate: Predicate): DataColumn = indices .filter { predicate(get(it)) } .let { get(it) } @@ -33,7 +33,7 @@ public inline fun DataColumn.filter(predicate: Predicate): DataColumn< // region DataFrame -public inline fun DataFrame.filter(predicate: RowFilter): DataFrame = +public inline fun DataFrame.filter(crossinline predicate: RowFilter): DataFrame = indices.filter { val row = get(it) predicate(row, row) 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 a37a18946e..7232367dd0 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 @@ -31,9 +31,9 @@ public fun DataColumn.first(): T = get(0) public fun DataColumn.firstOrNull(): T? = if (size > 0) first() else null -public inline fun DataColumn.first(predicate: (T) -> Boolean): T = values.first(predicate) +public fun DataColumn.first(predicate: (T) -> Boolean): T = values.first(predicate) -public inline fun DataColumn.firstOrNull(predicate: (T) -> Boolean): T? = values.firstOrNull(predicate) +public fun DataColumn.firstOrNull(predicate: (T) -> Boolean): T? = values.firstOrNull(predicate) // endregion @@ -48,9 +48,15 @@ public fun DataFrame.first(): DataRow { public fun DataFrame.firstOrNull(): DataRow? = if (nrow > 0) first() else null -public inline fun DataFrame.first(predicate: RowFilter): DataRow = rows().first { predicate(it, it) } +public inline fun DataFrame.first(crossinline predicate: RowFilter): DataRow = + rows().first { + predicate(it, it) + } -public inline fun DataFrame.firstOrNull(predicate: RowFilter): DataRow? = rows().firstOrNull { predicate(it, it) } +public inline fun DataFrame.firstOrNull(crossinline predicate: RowFilter): DataRow? = + rows().firstOrNull { + predicate(it, it) + } // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/format.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/format.kt index b7ed1ead61..c0813d101d 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/format.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/format.kt @@ -23,29 +23,29 @@ import kotlin.reflect.KProperty // region format -public inline fun DataFrame.format(noinline columns: ColumnsSelector): FormatClause = FormatClause(this, columns) +public fun DataFrame.format(columns: ColumnsSelector): FormatClause = FormatClause(this, columns) -public inline fun DataFrame.format(vararg columns: String): FormatClause = format { columns.toColumnSet() } +public fun DataFrame.format(vararg columns: String): FormatClause = format { columns.toColumnSet() } @AccessApiOverload -public inline fun DataFrame.format(vararg columns: ColumnReference): FormatClause = +public fun DataFrame.format(vararg columns: ColumnReference): FormatClause = format { columns.toColumnSet() } @AccessApiOverload -public inline fun DataFrame.format(vararg columns: KProperty): FormatClause = +public fun DataFrame.format(vararg columns: KProperty): FormatClause = format { columns.toColumnSet() } public fun DataFrame.format(): FormatClause = FormatClause(this) // endregion -public inline fun FormatClause.perRowCol(noinline formatter: RowColFormatter): FormattedFrame = +public fun FormatClause.perRowCol(formatter: RowColFormatter): FormattedFrame = formatImpl(formatter) -public inline fun FormatClause.with(noinline formatter: CellFormatter): FormattedFrame = +public fun FormatClause.with(formatter: CellFormatter): FormattedFrame = formatImpl { row, col -> formatter(row[col]) } -public inline fun FormatClause.where(noinline filter: RowValueFilter): FormatClause = +public fun FormatClause.where(filter: RowValueFilter): FormatClause = FormatClause(filter = filter, df = df, columns = columns, oldFormatter = oldFormatter) public fun FormattedFrame.format(): FormatClause = FormatClause(df, null, formatter) 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/groupBy.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/groupBy.kt index 3ad657f90a..eb5be20565 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/groupBy.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/groupBy.kt @@ -31,16 +31,16 @@ import kotlin.reflect.KProperty */ @Refine @Interpretable("DataFrameGroupBy") -public inline fun DataFrame.groupBy(moveToTop: Boolean = true, cols: ColumnsSelector): GroupBy = +public fun DataFrame.groupBy(moveToTop: Boolean = true, cols: ColumnsSelector): GroupBy = groupByImpl(moveToTop, cols) @AccessApiOverload -public inline fun DataFrame.groupBy(vararg cols: KProperty<*>): GroupBy = groupBy { cols.toColumnSet() } +public fun DataFrame.groupBy(vararg cols: KProperty<*>): GroupBy = groupBy { cols.toColumnSet() } -public inline fun DataFrame.groupBy(vararg cols: String): GroupBy = groupBy { cols.toColumnSet() } +public fun DataFrame.groupBy(vararg cols: String): GroupBy = groupBy { cols.toColumnSet() } @AccessApiOverload -public inline fun DataFrame.groupBy(vararg cols: AnyColumnReference, moveToTop: Boolean = true): GroupBy = +public fun DataFrame.groupBy(vararg cols: AnyColumnReference, moveToTop: Boolean = true): GroupBy = groupBy(moveToTop) { cols.toColumnSet() } // endregion 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..e278cb76ad 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,7 +9,7 @@ import org.jetbrains.kotlinx.dataframe.indices public fun AnyFrame.indices(): IntRange = 0 until rowsCount() -public fun DataFrame.indices(filter: RowFilter): List = +public inline fun DataFrame.indices(crossinline 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 32e4e8f78d..a0cd96fb63 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 @@ -39,10 +39,13 @@ public inline fun DataColumn.lastOrNull(predicate: (T) -> Boolean): T? = // region DataFrame -public inline fun DataFrame.lastOrNull(predicate: RowFilter): DataRow? = +public inline fun DataFrame.lastOrNull(crossinline predicate: RowFilter): DataRow? = rowsReversed().firstOrNull { predicate(it, it) } -public inline fun DataFrame.last(predicate: RowFilter): DataRow = rowsReversed().first { predicate(it, it) } +public inline fun DataFrame.last(crossinline 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 dc12f5fd5d..5a3f81a94c 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 @@ -33,7 +33,7 @@ public inline fun ColumnReference.map( public inline fun DataColumn.map( infer: Infer = Infer.Nulls, - crossinline transform: (T) -> R + crossinline transform: (T) -> R, ): DataColumn { val newValues = Array(size()) { transform(get(it)) }.asList() return DataColumn.createByType(name(), newValues, typeOf(), infer) @@ -42,7 +42,7 @@ public inline fun DataColumn.map( public inline fun DataColumn.map( type: KType, infer: Infer = Infer.Nulls, - crossinline transform: (T) -> R + crossinline transform: (T) -> R, ): DataColumn { val values = Array(size()) { transform(get(it)) }.asList() return DataColumn.createByType(name(), values, type, infer).cast() @@ -134,10 +134,10 @@ public inline fun GroupBy.map(crossinline body: Selector GroupBy.mapToRows(crossinline body: Selector, DataRow?>): DataFrame = +public fun GroupBy.mapToRows(body: Selector, DataRow?>): DataFrame = map(body).concat() -public inline fun GroupBy.mapToFrames(noinline body: Selector, DataFrame>): FrameColumn = +public fun GroupBy.mapToFrames(body: Selector, DataFrame>): FrameColumn = DataColumn.createFrameColumn(groups.name, map(body)) // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/max.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/max.kt index 6b194cdba7..3a127a562f 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/max.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/max.kt @@ -32,12 +32,14 @@ public fun > DataColumn.maxOrNull(): T? = asSequence().fil public inline fun > DataColumn.maxBy(selector: (T) -> R): T = maxByOrNull(selector).suggestIfNull("maxBy") -public inline fun > DataColumn.maxByOrNull(selector: (T) -> R): T? = values.maxByOrNull(selector) +public inline fun > DataColumn.maxByOrNull(selector: (T) -> R): T? = + values.maxByOrNull(selector) public inline fun > DataColumn.maxOf(selector: (T) -> R): R = maxOfOrNull(selector).suggestIfNull("maxOf") -public inline fun > DataColumn.maxOfOrNull(selector: (T) -> R): R? = values.maxOfOrNull(selector) +public inline fun > DataColumn.maxOfOrNull(selector: (T) -> R): R? = + values.maxOfOrNull(selector) // endregion @@ -97,10 +99,10 @@ public fun > DataFrame.maxOrNull(vararg columns: ColumnR public fun > DataFrame.maxOrNull(vararg columns: KProperty): C? = maxOrNull { columns.toColumnSet() } -public inline fun > DataFrame.maxOf(expression: RowExpression): C = +public inline fun > DataFrame.maxOf(crossinline expression: RowExpression): C = maxOfOrNull(expression).suggestIfNull("maxOf") -public inline fun > DataFrame.maxOfOrNull(expression: RowExpression): C? = +public inline fun > DataFrame.maxOfOrNull(crossinline expression: RowExpression): C? = rows().maxOfOrNull { expression(it, it) } public fun > DataFrame.maxBy(expression: RowExpression): DataRow = @@ -116,8 +118,9 @@ public fun > DataFrame.maxBy(column: ColumnReference public fun > DataFrame.maxBy(column: KProperty): DataRow = maxByOrNull(column).suggestIfNull("maxBy") -public fun > DataFrame.maxByOrNull(expression: RowExpression): DataRow? = - getOrNull(rows().asSequence().map { expression(it, it) }.indexOfMax()) +public inline fun > DataFrame.maxByOrNull( + crossinline expression: RowExpression, +): DataRow? = getOrNull(rows().asSequence().map { expression(it, it) }.indexOfMax()) public fun DataFrame.maxByOrNull(column: String): DataRow? = maxByOrNull(column.toColumnOf?>()) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/min.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/min.kt index 8b0b971669..64db11e01d 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/min.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/min.kt @@ -32,12 +32,14 @@ public fun > DataColumn.minOrNull(): T? = asSequence().fil public inline fun > DataColumn.minBy(selector: (T) -> R): T = minByOrNull(selector).suggestIfNull("minBy") -public inline fun > DataColumn.minByOrNull(selector: (T) -> R): T? = values.minByOrNull(selector) +public inline fun > DataColumn.minByOrNull(selector: (T) -> R): T? = + values.minByOrNull(selector) public inline fun > DataColumn.minOf(selector: (T) -> R): R = minOfOrNull(selector).suggestIfNull("minOf") -public inline fun > DataColumn.minOfOrNull(selector: (T) -> R): R? = values.minOfOrNull(selector) +public inline fun > DataColumn.minOfOrNull(selector: (T) -> R): R? = + values.minOfOrNull(selector) // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt index 889d39879e..956a5a5f66 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt @@ -64,7 +64,8 @@ private interface CommonSelectDocs */ @Refine @Interpretable("Select0") -public inline fun DataFrame.select(noinline columns: ColumnsSelector): DataFrame = get(columns).toDataFrame().cast() +public inline fun DataFrame.select(noinline columns: ColumnsSelector): DataFrame = + get(columns).toDataFrame().cast() /** * @include [CommonSelectDocs] 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..eb37bbf788 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(crossinline predicate: RowExpression): DataRow = rows().single { predicate(it, it) } -public fun DataFrame.singleOrNull(predicate: RowExpression): DataRow? = +public inline fun DataFrame.singleOrNull(crossinline predicate: RowExpression): DataRow? = rows().singleOrNull { predicate(it, it) } // endregion diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/sort.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/sort.kt index 36a2b048c3..c8b6579e70 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/sort.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/sort.kt @@ -100,7 +100,7 @@ public fun > C.sortWith(comparator: Comparator): C = DataColumn.createByType(name, values().sortedWith(comparator), type) as C /** @include [CommonDataColumnSortWithDocs] */ -public inline fun > C.sortWith(noinline comparator: (T, T) -> Int): C = sortWith(Comparator(comparator)) +public fun > C.sortWith(comparator: (T, T) -> Int): C = sortWith(Comparator(comparator)) // endregion @@ -122,7 +122,7 @@ public fun DataFrame.sortWith(comparator: Comparator>): DataFr return this[permutation] } -public inline fun DataFrame.sortWith(noinline comparator: (DataRow, DataRow) -> Int): DataFrame = +public fun DataFrame.sortWith(comparator: (DataRow, DataRow) -> Int): DataFrame = sortWith(Comparator(comparator)) public fun DataFrame.sortByDesc(columns: SortColumnsSelector): DataFrame { 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 5f9161f47f..c11d7e951f 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() @@ -269,8 +274,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 52c3594fa4..03c746cada 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,7 +60,7 @@ public fun DataFrame.takeLast(n: Int = 1): DataFrame { /** * Returns a DataFrame containing first rows that satisfy the given [predicate]. */ -public inline fun DataFrame.takeWhile(predicate: RowFilter): DataFrame = +public inline fun DataFrame.takeWhile(crossinline 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/update.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/update.kt index 230087a22e..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 inline fun Update.with(noinline 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/impl/Utils.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/Utils.kt index e16ce32433..2ff0c2499c 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/Utils.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/Utils.kt @@ -246,6 +246,7 @@ internal fun > Sequence.indexOfMin(): Int { return minIndex } +@PublishedApi internal fun > Sequence.indexOfMax(): Int { val iterator = iterator() if (!iterator.hasNext()) return -1 diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/describe.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/describe.kt index 08ea27a182..00adf85b3a 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/describe.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/describe.kt @@ -117,12 +117,11 @@ private fun DataColumn.convertToComparableOrNull(): DataColumn asComparable() // Found incomparable number types, convert all to Double first - isNumber() -> cast().map { - if (it?.isPrimitiveNumber() == false) { - // Cannot calculate statistics of a non-primitive number type + isNumber() -> with(cast()) { + if (any { it?.isPrimitiveNumber() == false }) { return@convertToComparableOrNull null } - it?.toDouble() as Comparable? + map { it?.toDouble() as Comparable? } } else -> null 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/api/joinWith.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/joinWith.kt index 290b8be2e4..ca92b06690 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/joinWith.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/joinWith.kt @@ -25,7 +25,7 @@ internal class JoinedDataRowImpl( override val right: DataRow = DataRowImpl(index1, rightOwner) } -internal fun DataFrame.joinWithImpl( +internal inline fun DataFrame.joinWithImpl( right: DataFrame, type: JoinType = JoinType.Inner, addNewColumns: Boolean, 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) From 0f9856e5938b7d33885296bc4b218df1fd1f175d Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Fri, 28 Mar 2025 16:54:36 +0400 Subject: [PATCH 3/6] remove unnecessary crossinline --- core/api/core.api | 5 ----- .../jetbrains/kotlinx/dataframe/DataFrame.kt | 2 -- .../jetbrains/kotlinx/dataframe/DataRow.kt | 2 -- .../kotlinx/dataframe/api/DataRowApi.kt | 19 ++++++++----------- .../jetbrains/kotlinx/dataframe/api/all.kt | 4 ++-- .../jetbrains/kotlinx/dataframe/api/any.kt | 2 +- .../kotlinx/dataframe/api/associate.kt | 4 ++-- .../jetbrains/kotlinx/dataframe/api/count.kt | 4 ++-- .../jetbrains/kotlinx/dataframe/api/drop.kt | 7 +++---- .../jetbrains/kotlinx/dataframe/api/filter.kt | 6 +++--- .../jetbrains/kotlinx/dataframe/api/first.kt | 4 ++-- .../kotlinx/dataframe/api/indices.kt | 4 ++-- .../jetbrains/kotlinx/dataframe/api/last.kt | 4 ++-- .../jetbrains/kotlinx/dataframe/api/map.kt | 16 ++++++---------- .../jetbrains/kotlinx/dataframe/api/select.kt | 7 +++---- .../jetbrains/kotlinx/dataframe/api/single.kt | 4 ++-- .../jetbrains/kotlinx/dataframe/api/take.kt | 2 +- 17 files changed, 39 insertions(+), 57 deletions(-) diff --git a/core/api/core.api b/core/api/core.api index fb7793d5d5..c4f356c48c 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -104,7 +104,6 @@ public final class org/jetbrains/kotlinx/dataframe/DataFrameKt { public static final fun get (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public static final fun get (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/ranges/ClosedRange;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; public static final fun get (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;[Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; - public static final fun getIndices (Lorg/jetbrains/kotlinx/dataframe/DataFrame;)Lkotlin/ranges/IntRange; public static final fun size (Lorg/jetbrains/kotlinx/dataframe/DataFrame;)Lorg/jetbrains/kotlinx/dataframe/impl/DataFrameSize; } @@ -164,10 +163,6 @@ public final class org/jetbrains/kotlinx/dataframe/DataRow$Companion { public final fun getEmpty ()Lorg/jetbrains/kotlinx/dataframe/DataRow; } -public final class org/jetbrains/kotlinx/dataframe/DataRowKt { - public static final fun getIndex (Lorg/jetbrains/kotlinx/dataframe/DataRow;)I -} - public abstract interface class org/jetbrains/kotlinx/dataframe/aggregation/Aggregatable { } diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataFrame.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataFrame.kt index fc241733ae..e4825537f8 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataFrame.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataFrame.kt @@ -135,8 +135,6 @@ public operator fun DataFrame.get(columnRange: ClosedRange): Data internal val ColumnsContainer<*>.ncol get() = columnsCount() internal val AnyFrame.nrow get() = rowsCount() - -@PublishedApi internal val AnyFrame.indices get() = indices() internal val AnyFrame.size: DataFrameSize get() = size() diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataRow.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataRow.kt index a338622972..8be75df4e3 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataRow.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataRow.kt @@ -149,8 +149,6 @@ public interface DataRow { } internal val AnyRow.values: List get() = values() - -@PublishedApi internal val AnyRow.index: Int get() = index() internal val DataRow.prev: DataRow? get() = this.prev() internal val DataRow.next: DataRow? get() = this.next() 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 5804dc26fd..b1bb7a9cc1 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,10 +111,7 @@ internal interface DiffOrNullDocs */ @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType -public inline fun DataRow.diff( - firstRowResult: Double, - crossinline expression: RowExpression, -): Double = +public inline fun DataRow.diff(firstRowResult: Double, expression: RowExpression): Double = prev()?.let { p -> expression(this, this) - expression(p, p) } ?: firstRowResult @@ -124,21 +121,21 @@ public inline fun DataRow.diff( @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType // required to resolve `diff(0) { intValue }` -public inline fun DataRow.diff(firstRowResult: Int, crossinline 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 inline fun DataRow.diff(firstRowResult: Long, crossinline 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 inline fun DataRow.diff(firstRowResult: Float, crossinline expression: RowExpression): Float = +public inline fun DataRow.diff(firstRowResult: Float, expression: RowExpression): Float = prev()?.let { p -> expression(this, this) - expression(p, p) } ?: firstRowResult @@ -147,25 +144,25 @@ public inline fun DataRow.diff(firstRowResult: Float, crossinline express */ @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType -public inline fun DataRow.diffOrNull(crossinline expression: RowExpression): Double? = +public inline fun DataRow.diffOrNull(expression: RowExpression): Double? = prev()?.let { p -> expression(this, this) - expression(p, p) } /** * @include [DiffOrNullDocs] */ -public inline fun DataRow.diffOrNull(crossinline expression: RowExpression): Int? = +public inline fun DataRow.diffOrNull(expression: RowExpression): Int? = prev()?.let { p -> expression(this, this) - expression(p, p) } /** * @include [DiffOrNullDocs] */ -public inline fun DataRow.diffOrNull(crossinline expression: RowExpression): Long? = +public inline fun DataRow.diffOrNull(expression: RowExpression): Long? = prev()?.let { p -> expression(this, this) - expression(p, p) } /** * @include [DiffOrNullDocs] */ -public inline fun DataRow.diffOrNull(crossinline 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 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 5e9fedfa3e..c3370409e3 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 @@ -51,7 +51,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 inline fun DataFrame.all(crossinline predicate: RowFilter): Boolean = rows().all { predicate(it, it) } +public inline fun DataFrame.all(predicate: RowFilter): Boolean = rows().all { predicate(it, it) } // endregion @@ -1243,7 +1243,7 @@ internal inline fun ColumnsResolver<*>.allFromInternal(crossinline colByPredicat * @return a new ColumnSet containing all columns that come before the first column that satisfies the given predicate */ @PublishedApi -internal fun ColumnsResolver<*>.allBeforeInternal(colByPredicate: ColumnFilter<*>): ColumnSet<*> { +internal inline fun ColumnsResolver<*>.allBeforeInternal(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 3bb56f3bac..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 inline fun DataFrame.any(crossinline 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 475b5926e6..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 inline fun DataFrame.associateBy(crossinline transform: RowExpression): Map> = +public inline fun DataFrame.associateBy(transform: RowExpression): Map> = rows().associateBy { transform(it, it) } -public inline fun DataFrame.associate(crossinline 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/count.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/count.kt index 50920ca041..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 inline fun AnyRow.count(crossinline predicate: Predicate): Int = values().count(predicate) +public inline fun AnyRow.count(predicate: Predicate): Int = values().count(predicate) // endregion @@ -33,7 +33,7 @@ public inline fun AnyRow.count(crossinline predicate: Predicate): Int = va public fun DataFrame.count(): Int = rowsCount() -public inline fun DataFrame.count(crossinline predicate: RowFilter): Int = rows().count { predicate(it, it) } +public inline fun DataFrame.count(predicate: RowFilter): Int = rows().count { predicate(it, it) } // 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 bc227b113a..e33637d1a7 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 @@ -23,7 +23,7 @@ import kotlin.reflect.KProperty // region DataColumn -public inline fun DataColumn.drop(crossinline 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 { @@ -61,14 +61,13 @@ public fun DataFrame.dropLast(n: Int = 1): DataFrame { /** * Returns a DataFrame containing all rows except rows that satisfy the given [predicate]. */ -public inline fun DataFrame.drop(crossinline 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 inline fun DataFrame.dropWhile(crossinline predicate: RowFilter): DataFrame = - firstOrNull { !predicate(it, it) }?.let { drop(it.index) } ?: this + firstOrNull { !predicate(it, it) }?.let { drop(it.index()) } ?: this // endregion 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 d352f1475f..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 inline fun DataColumn.filter(crossinline predicate: Predicate): DataColumn = +public inline fun DataColumn.filter(predicate: Predicate): DataColumn = indices .filter { predicate(get(it)) } .let { get(it) } @@ -33,8 +33,8 @@ public inline fun DataColumn.filter(crossinline predicate: Predicate): // region DataFrame -public inline fun DataFrame.filter(crossinline 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 7232367dd0..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,12 +48,12 @@ public fun DataFrame.first(): DataRow { public fun DataFrame.firstOrNull(): DataRow? = if (nrow > 0) first() else null -public inline fun DataFrame.first(crossinline predicate: RowFilter): DataRow = +public inline fun DataFrame.first(predicate: RowFilter): DataRow = rows().first { predicate(it, it) } -public inline fun DataFrame.firstOrNull(crossinline predicate: RowFilter): DataRow? = +public inline fun DataFrame.firstOrNull(predicate: RowFilter): DataRow? = rows().firstOrNull { predicate(it, it) } 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 e278cb76ad..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 inline fun DataFrame.indices(crossinline 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 a0cd96fb63..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 @@ -39,10 +39,10 @@ public inline fun DataColumn.lastOrNull(predicate: (T) -> Boolean): T? = // region DataFrame -public inline fun DataFrame.lastOrNull(crossinline predicate: RowFilter): DataRow? = +public inline fun DataFrame.lastOrNull(predicate: RowFilter): DataRow? = rowsReversed().firstOrNull { predicate(it, it) } -public inline fun DataFrame.last(crossinline predicate: RowFilter): DataRow = +public inline fun DataFrame.last(predicate: RowFilter): DataRow = rowsReversed().first { predicate(it, it) } 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 5a3f81a94c..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 @@ -31,10 +31,7 @@ public inline fun ColumnReference.map( // region DataColumn -public inline fun DataColumn.map( - infer: Infer = Infer.Nulls, - crossinline transform: (T) -> R, -): DataColumn { +public inline fun DataColumn.map(infer: Infer = Infer.Nulls, transform: (T) -> R): DataColumn { val newValues = Array(size()) { transform(get(it)) }.asList() return DataColumn.createByType(name(), newValues, typeOf(), infer) } @@ -42,7 +39,7 @@ public inline fun DataColumn.map( public inline fun DataColumn.map( type: KType, infer: Infer = Infer.Nulls, - crossinline transform: (T) -> R, + transform: (T) -> R, ): DataColumn { val values = Array(size()) { transform(get(it)) }.asList() return DataColumn.createByType(name(), values, type, infer).cast() @@ -50,7 +47,7 @@ public inline fun DataColumn.map( 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) @@ -59,7 +56,7 @@ public inline fun DataColumn.mapIndexed( public inline fun DataColumn.mapIndexed( type: KType, infer: Infer = Infer.Nulls, - crossinline transform: (Int, T) -> R, + transform: (Int, T) -> R, ): DataColumn { val values = Array(size()) { transform(it, get(it)) }.asList() return DataColumn.createByType(name(), values, type, infer).cast() @@ -69,8 +66,7 @@ public inline fun DataColumn.mapIndexed( // region DataFrame -public inline fun DataFrame.map(crossinline 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, @@ -127,7 +123,7 @@ public inline fun DataFrame.mapToFrame(body: AddDsl.() -> Unit): AnyFr // region GroupBy -public inline fun GroupBy.map(crossinline 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/select.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt index 956a5a5f66..59295da93c 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt @@ -64,8 +64,7 @@ private interface CommonSelectDocs */ @Refine @Interpretable("Select0") -public inline fun DataFrame.select(noinline columns: ColumnsSelector): DataFrame = - get(columns).toDataFrame().cast() +public fun DataFrame.select(columns: ColumnsSelector): DataFrame = get(columns).toDataFrame().cast() /** * @include [CommonSelectDocs] @@ -73,14 +72,14 @@ public inline fun DataFrame.select(noinline columns: ColumnsSelector DataFrame.select(vararg columns: KProperty<*>): DataFrame = select { columns.toColumnSet() } +public fun DataFrame.select(vararg columns: KProperty<*>): DataFrame = select { columns.toColumnSet() } /** * @include [CommonSelectDocs] * @include [SelectingColumns.ColumnNames.WithExample] {@include [SetSelectOperationArg]} * @param [columns] The [Column Names][String] used to select the columns of this [DataFrame]. */ -public inline fun DataFrame.select(vararg columns: String): DataFrame = select { columns.toColumnSet() } +public fun DataFrame.select(vararg columns: String): DataFrame = select { columns.toColumnSet() } /** * @include [CommonSelectDocs] 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 eb37bbf788..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 inline fun DataFrame.single(crossinline predicate: RowExpression): DataRow = +public inline fun DataFrame.single(predicate: RowExpression): DataRow = rows().single { predicate(it, it) } -public inline fun DataFrame.singleOrNull(crossinline 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/take.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/take.kt index 03c746cada..0239540c4e 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 @@ -61,7 +61,7 @@ public fun DataFrame.takeLast(n: Int = 1): DataFrame { * Returns a DataFrame containing first rows that satisfy the given [predicate]. */ public inline fun DataFrame.takeWhile(crossinline predicate: RowFilter): DataFrame = - firstOrNull { !predicate(it, it) }?.let { take(it.index) } ?: this + firstOrNull { !predicate(it, it) }?.let { take(it.index()) } ?: this // endregion From 0b22f16977c5ebdc098e8ae6da9553f4ec0fac67 Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Mon, 7 Apr 2025 14:23:24 +0400 Subject: [PATCH 4/6] remove unneeded crossinlines --- core/api/core.api | 1 - .../kotlinx/dataframe/api/DataRowApi.kt | 2 +- .../jetbrains/kotlinx/dataframe/api/drop.kt | 2 +- .../kotlinx/dataframe/api/duplicate.kt | 2 +- .../jetbrains/kotlinx/dataframe/api/group.kt | 172 ++++++++++++++++++ .../jetbrains/kotlinx/dataframe/api/take.kt | 2 +- .../kotlinx/dataframe/api/ungroup.kt | 46 +++++ .../documentation/DocumentationUrls.kt | 6 + .../kotlinx/dataframe/impl/api/describe.kt | 6 +- .../kotlinx/dataframe/impl/api/joinWith.kt | 2 +- 10 files changed, 232 insertions(+), 9 deletions(-) diff --git a/core/api/core.api b/core/api/core.api index 8784e0c2e1..64b04c6b20 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -5427,7 +5427,6 @@ public final class org/jetbrains/kotlinx/dataframe/impl/UtilsKt { public static final fun headPlusArray (J[J)[J public static final fun headPlusArray (S[S)[S public static final fun headPlusArray (Z[Z)[Z - public static final fun indexOfMax (Lkotlin/sequences/Sequence;)I public static final fun toCamelCaseByDelimiters (Ljava/lang/String;Lkotlin/text/Regex;Ljava/lang/String;)Ljava/lang/String; public static synthetic fun toCamelCaseByDelimiters$default (Ljava/lang/String;Lkotlin/text/Regex;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String; public static final fun zero (Lkotlin/reflect/KClass;)Ljava/lang/Number; 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 b1bb7a9cc1..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 @@ -205,7 +205,7 @@ public fun DataRow.relative(relativeIndices: IntRange): DataFrame = (relativeIndices.first + index).coerceIn(df().indices)..(relativeIndices.last + index).coerceIn(df().indices), ) -public inline fun DataRow.movingAverage(k: Int, crossinline 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/drop.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/drop.kt index e1ed16baab..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 @@ -67,7 +67,7 @@ public inline fun DataFrame.drop(predicate: RowFilter): DataFrame = /** * Returns a DataFrame containing all rows except first rows that satisfy the given [predicate]. */ -public inline fun DataFrame.dropWhile(crossinline predicate: RowFilter): DataFrame = +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 e7db27d8f1..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 inline fun DataFrame.duplicateRows(n: Int, crossinline 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/group.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/group.kt index a98ba0b6f5..7fb05c97b1 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,102 @@ 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]} + * + * [**`into`**][GroupClause.into]**`(`**`groupName: `[`String`][String]**`)`** + * + * {@include [Indent]} + * __`.`__[**`into`**][GroupClause.into]**` { `**`groupNameExpression: `[`ColumnsSelector`][ColumnsSelector]**` } `** + */ + 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 +116,110 @@ 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 + * 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: + * df.group("age", "weight").into { info } + * // Group selected columns into a nested column group using a path that may + * // contain both existing and new segments: + * df.group { employee.age and employee.weight }.into { pathOf("info", "personal") } + * // Group selected columns under their ancestor group located two levels up in the path hierarchy + * 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/take.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/take.kt index 0239540c4e..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,7 +60,7 @@ public fun DataFrame.takeLast(n: Int = 1): DataFrame { /** * Returns a DataFrame containing first rows that satisfy the given [predicate]. */ -public inline fun DataFrame.takeWhile(crossinline predicate: RowFilter): DataFrame = +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..0996cd15e7 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,65 @@ 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]} + */ +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/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/describe.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/describe.kt index 00adf85b3a..85eae2909b 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/describe.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/describe.kt @@ -118,10 +118,10 @@ private fun DataColumn.convertToComparableOrNull(): DataColumn with(cast()) { - if (any { it?.isPrimitiveNumber() == false }) { - return@convertToComparableOrNull null + map { + if (it?.isPrimitiveNumber() == false) return@convertToComparableOrNull null + it?.toDouble() as Comparable? } - map { it?.toDouble() as Comparable? } } else -> null diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/joinWith.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/joinWith.kt index ca92b06690..290b8be2e4 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/joinWith.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/joinWith.kt @@ -25,7 +25,7 @@ internal class JoinedDataRowImpl( override val right: DataRow = DataRowImpl(index1, rightOwner) } -internal inline fun DataFrame.joinWithImpl( +internal fun DataFrame.joinWithImpl( right: DataFrame, type: JoinType = JoinType.Inner, addNewColumns: Boolean, From 5bc9783bd89c328c07806725a312c373411c5eac Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Thu, 10 Apr 2025 16:14:30 +0400 Subject: [PATCH 5/6] group kdocs fix --- .../org/jetbrains/kotlinx/dataframe/api/group.kt | 14 +++++++++----- .../org/jetbrains/kotlinx/dataframe/api/ungroup.kt | 2 ++ .../kotlinx/dataframe/impl/api/describe.kt | 9 +++++---- 3 files changed, 16 insertions(+), 9 deletions(-) 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 7fb05c97b1..535c94dedd 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 @@ -61,7 +61,10 @@ internal interface GroupDocs { * {@include [DslGrammarLink]} * {@include [LineBreak]} * - * [**`into`**][GroupClause.into]**`(`**`groupName: `[`String`][String]**`)`** + * **[`group`][group]****` { `**`columnsSelector: `[`ColumnsSelector`][ColumnsSelector]**` }`** + * + * {@include [Indent]} + * __`.`__[**`into`**][GroupClause.into]**`(`**`groupName: `[`String`][String]**`)`** * * {@include [Indent]} * __`.`__[**`into`**][GroupClause.into]**` { `**`groupNameExpression: `[`ColumnsSelector`][ColumnsSelector]**` } `** @@ -181,12 +184,13 @@ public fun GroupClause.into(column: ColumnsSelectionDsl.(ColumnW * * ### Examples: * ```kotlin - * // Group selected columns into an existing column group: + * // 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 that may - * // contain both existing and new segments: + * + * // 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") } - * // Group selected columns under their ancestor group located two levels up in the path hierarchy + * + * // 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) } * ``` * 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 0996cd15e7..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 @@ -24,6 +24,8 @@ import kotlin.reflect.KProperty * See [Selecting Columns][UngroupSelectingOptions]. * * For more information: {@include [DocumentationUrls.Ungroup]} + * + * Reverse operation: [group]. */ internal interface UngroupDocs { /** diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/describe.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/describe.kt index 85eae2909b..08ea27a182 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/describe.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/describe.kt @@ -117,11 +117,12 @@ private fun DataColumn.convertToComparableOrNull(): DataColumn asComparable() // Found incomparable number types, convert all to Double first - isNumber() -> with(cast()) { - map { - if (it?.isPrimitiveNumber() == false) return@convertToComparableOrNull null - it?.toDouble() as Comparable? + isNumber() -> cast().map { + if (it?.isPrimitiveNumber() == false) { + // Cannot calculate statistics of a non-primitive number type + return@convertToComparableOrNull null } + it?.toDouble() as Comparable? } else -> null From cd181a6de745313feed454f29cf71bb7d9c4863c Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Thu, 10 Apr 2025 16:58:01 +0400 Subject: [PATCH 6/6] fix group grammar --- .../kotlin/org/jetbrains/kotlinx/dataframe/api/group.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 535c94dedd..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 @@ -67,7 +67,11 @@ internal interface GroupDocs { * __`.`__[**`into`**][GroupClause.into]**`(`**`groupName: `[`String`][String]**`)`** * * {@include [Indent]} - * __`.`__[**`into`**][GroupClause.into]**` { `**`groupNameExpression: `[`ColumnsSelector`][ColumnsSelector]**` } `** + * __`.`__[**`into`**][GroupClause.into]` { column: `[`ColumnsSelectionDsl`][ColumnsSelectionDsl]`.(`[`ColumnWithPath`][ColumnWithPath]`) -> `[`String`][String]` }` + * + * {@include [Indent]} + * __`.`__[**`into`**][GroupClause.into]` { column: `[`ColumnsSelectionDsl`][ColumnsSelectionDsl]`.(`[`ColumnWithPath`][ColumnWithPath]`) -> `[`AnyColumnReference`][AnyColumnReference]` }` + * */ interface Grammar } @@ -156,6 +160,7 @@ public class GroupClause(internal val df: DataFrame, internal val colum * * ### 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() } * ``` *