diff --git a/core/api/core.api b/core/api/core.api index f764cd4945..fe2d668a07 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -2359,11 +2359,13 @@ public final class org/jetbrains/kotlinx/dataframe/api/Gather { public fun (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/reflect/KType;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Z)V public synthetic fun (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/reflect/KType;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun cast ()Lorg/jetbrains/kotlinx/dataframe/api/Gather; - public final fun copy (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/reflect/KType;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Z)Lorg/jetbrains/kotlinx/dataframe/api/Gather; - public static synthetic fun copy$default (Lorg/jetbrains/kotlinx/dataframe/api/Gather;Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/reflect/KType;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ZILjava/lang/Object;)Lorg/jetbrains/kotlinx/dataframe/api/Gather; - public fun equals (Ljava/lang/Object;)Z - public fun hashCode ()I - public fun toString ()Ljava/lang/String; + public final fun getColumns ()Lkotlin/jvm/functions/Function2; + public final fun getDf ()Lorg/jetbrains/kotlinx/dataframe/DataFrame; + public final fun getExplode ()Z + public final fun getFilter ()Lkotlin/jvm/functions/Function2; + public final fun getKeyTransform ()Lkotlin/jvm/functions/Function1; + public final fun getKeyType ()Lkotlin/reflect/KType; + public final fun getValueTransform ()Lkotlin/jvm/functions/Function1; } public final class org/jetbrains/kotlinx/dataframe/api/GatherKt { @@ -5463,7 +5465,7 @@ public final class org/jetbrains/kotlinx/dataframe/exceptions/CellConversionExce public final fun getRow ()Ljava/lang/Integer; } -public final class org/jetbrains/kotlinx/dataframe/exceptions/ColumnNotFoundException : java/lang/RuntimeException, org/jetbrains/kotlinx/dataframe/exceptions/DataFrameException { +public final class org/jetbrains/kotlinx/dataframe/exceptions/ColumnNotFoundException : java/lang/RuntimeException, org/jetbrains/kotlinx/dataframe/exceptions/DataFrameError { public fun (Ljava/lang/String;Ljava/lang/String;)V public final fun getColumnName ()Ljava/lang/String; public fun getMessage ()Ljava/lang/String; @@ -5474,11 +5476,11 @@ public final class org/jetbrains/kotlinx/dataframe/exceptions/ColumnTypeMismatch public final fun getColumn ()Lorg/jetbrains/kotlinx/dataframe/DataColumn; } -public abstract interface class org/jetbrains/kotlinx/dataframe/exceptions/DataFrameException { +public abstract interface class org/jetbrains/kotlinx/dataframe/exceptions/DataFrameError { public abstract fun getMessage ()Ljava/lang/String; } -public final class org/jetbrains/kotlinx/dataframe/exceptions/DuplicateColumnNamesException : java/lang/IllegalArgumentException, org/jetbrains/kotlinx/dataframe/exceptions/DataFrameException { +public final class org/jetbrains/kotlinx/dataframe/exceptions/DuplicateColumnNamesException : java/lang/IllegalArgumentException, org/jetbrains/kotlinx/dataframe/exceptions/DataFrameError { public fun (Ljava/util/List;)V public final fun getAllColumnNames ()Ljava/util/List; public final fun getDuplicatedNames ()Ljava/util/List; @@ -5755,6 +5757,10 @@ public final class org/jetbrains/kotlinx/dataframe/impl/aggregation/receivers/Ag public static final fun internal (Lorg/jetbrains/kotlinx/dataframe/aggregation/AggregateDsl;)Lorg/jetbrains/kotlinx/dataframe/impl/aggregation/receivers/AggregateInternalDsl; } +public final class org/jetbrains/kotlinx/dataframe/impl/api/ConstructorsKt { + public static final fun withValuesImpl (Lkotlin/Pair;)Ljava/util/List; +} + public final class org/jetbrains/kotlinx/dataframe/impl/api/ConvertKt { public static final fun convertRowColumnImpl (Lorg/jetbrains/kotlinx/dataframe/api/Convert;Lkotlin/reflect/KType;Lorg/jetbrains/kotlinx/dataframe/api/Infer;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; public static final fun withRowCellImpl (Lorg/jetbrains/kotlinx/dataframe/api/Convert;Lkotlin/reflect/KType;Lorg/jetbrains/kotlinx/dataframe/api/Infer;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/constructors.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/constructors.kt index 37bf0994ad..cfecd4fcf9 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/constructors.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/constructors.kt @@ -393,7 +393,7 @@ public class DataFrameBuilder(private val header: List) { @JvmName("invoke1") internal fun withValues(values: Iterable): DataFrame<*> = - withValuesImpl(header, values.asList()).map { (name, values) -> + (header to values.asList()).withValuesImpl().map { (name, values) -> DataColumn.createByInference(name, values) }.toDataFrame() diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/gather.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/gather.kt index 76042d293f..bfe9b3c090 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/gather.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/gather.kt @@ -4,6 +4,8 @@ import org.jetbrains.kotlinx.dataframe.ColumnsSelector import org.jetbrains.kotlinx.dataframe.DataFrame import org.jetbrains.kotlinx.dataframe.RowValueFilter 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.ColumnAccessor import org.jetbrains.kotlinx.dataframe.columns.ColumnReference import org.jetbrains.kotlinx.dataframe.columns.toColumnSet @@ -15,6 +17,7 @@ import kotlin.reflect.typeOf // region gather +@Interpretable("Gather0") public fun DataFrame.gather(selector: ColumnsSelector): Gather = Gather( df = this, @@ -44,30 +47,76 @@ public fun DataFrame.gather(vararg columns: KProperty): Gather Gather.where(filter: RowValueFilter): Gather = - copy(filter = this.filter and filter) + Gather( + df = df, + columns = columns, + filter = this.filter and filter, + keyType = keyType, + keyTransform = keyTransform, + valueTransform = valueTransform, + explode = explode, + ) +@Interpretable("GatherChangeType") public fun Gather.notNull(): Gather = where { it != null } as Gather -public fun Gather.explodeLists(): Gather = copy(explode = true) +@Interpretable("GatherExplodeLists") +public fun Gather.explodeLists(): Gather = + Gather( + df = df, + columns = columns, + filter = filter, + keyType = keyType, + keyTransform = keyTransform, + valueTransform = valueTransform, + explode = true, + ) +@Interpretable("GatherMap") public inline fun Gather.mapKeys( noinline transform: (String) -> K, ): Gather = - copy(keyTransform = transform as ((String) -> Nothing), keyType = typeOf()) as Gather + Gather( + df = df, + columns = columns, + filter = filter, + keyType = typeOf(), + keyTransform = transform, + valueTransform = valueTransform, + explode = explode, + ) +@Interpretable("GatherMap") public fun Gather.mapValues(transform: (C) -> R): Gather = - copy(valueTransform = transform as ((C) -> Nothing)) as Gather + Gather( + df = df, + columns = columns, + filter = filter, + keyType = keyType, + keyTransform = keyTransform, + valueTransform = transform, + explode = explode, + ) -public data class Gather( +public class Gather( + @PublishedApi internal val df: DataFrame, + @PublishedApi internal val columns: ColumnsSelector, + @PublishedApi internal val filter: RowValueFilter? = null, + @PublishedApi internal val keyType: KType? = null, + @PublishedApi internal val keyTransform: ((String) -> K), + @PublishedApi internal val valueTransform: ((C) -> R)? = null, + @PublishedApi internal val explode: Boolean = false, ) { + @Interpretable("GatherChangeType") public fun

cast(): Gather { // TODO: introduce GatherWithTransform to avoid this error require(valueTransform == null) { "Cast is not allowed to be called after `mapValues`" } @@ -77,6 +126,8 @@ public data class Gather( // region into +@Refine +@Interpretable("GatherInto") public fun Gather.into(keyColumn: String, valueColumn: String): DataFrame = gatherImpl(keyColumn, valueColumn) @@ -100,6 +151,8 @@ public fun Gather.into(keyColumn: KProperty, valueCo // region keysInto +@Refine +@Interpretable("GatherKeysInto") public fun Gather.keysInto(keyColumn: String): DataFrame = gatherImpl(keyColumn, null) @Deprecated( @@ -120,6 +173,8 @@ public fun Gather.keysInto(keyColumn: KProperty): Da // region valuesInto +@Refine +@Interpretable("GatherValuesInto") public fun Gather.valuesInto(valueColumn: String): DataFrame = gatherImpl(null, valueColumn) @Deprecated( diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/ColumnNotFoundException.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/ColumnNotFoundException.kt index 7d037acffa..91b61f4117 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/ColumnNotFoundException.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/ColumnNotFoundException.kt @@ -2,4 +2,4 @@ package org.jetbrains.kotlinx.dataframe.exceptions public class ColumnNotFoundException(public val columnName: String, public override val message: String) : RuntimeException(), - DataFrameException + DataFrameError diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/DataFrameException.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/DataFrameError.kt similarity index 53% rename from core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/DataFrameException.kt rename to core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/DataFrameError.kt index 4d3529e5d9..b0dfc17f77 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/DataFrameException.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/DataFrameError.kt @@ -1,8 +1,9 @@ package org.jetbrains.kotlinx.dataframe.exceptions /** - * If DataFrame function used by compiler plugin as implementation detail throws this exception, [message] will be reported as warning + * If DataFrame function used by compiler plugin as implementation detail throws exception + * that implements this interface, [message] will be reported as warning */ -public interface DataFrameException { +public interface DataFrameError { public val message: String } diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/DuplicateColumnNamesException.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/DuplicateColumnNamesException.kt index 890d9547cb..2e219a02e4 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/DuplicateColumnNamesException.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/exceptions/DuplicateColumnNamesException.kt @@ -2,7 +2,7 @@ package org.jetbrains.kotlinx.dataframe.exceptions public class DuplicateColumnNamesException(public val allColumnNames: List) : IllegalArgumentException(), - DataFrameException { + DataFrameError { public val duplicatedNames: List = allColumnNames .groupBy { it } diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/constructors.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/constructors.kt index ba166e3e2e..30495180e1 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/constructors.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/constructors.kt @@ -1,10 +1,16 @@ package org.jetbrains.kotlinx.dataframe.impl.api -internal fun withValuesImpl(header: List, values: List): List>> { +import org.jetbrains.kotlinx.dataframe.exceptions.DataFrameError + +/** + * Public API to be re-used in compiler plugin implementation + */ +public fun Pair, List>.withValuesImpl(): List>> { + val (header, values) = this val ncol = header.size - require(header.isNotEmpty() && values.size.rem(ncol) == 0) { - "Number of values ${values.size} is not divisible by number of columns $ncol" + if (!(header.isNotEmpty() && values.size.rem(ncol) == 0)) { + throw WrongNumberOfValuesException(values.size, ncol) } val nrow = values.size / ncol @@ -16,3 +22,9 @@ internal fun withValuesImpl(header: List, values: List): List + val columns = (receiver.header to values.arguments).withValuesImpl().map { (name, values) -> val type = session.typeContext.commonSuperTypeOrNull(values.map { it.resolvedType }) ?: error("$name $values") simpleColumnOf(name, type) }