Skip to content

Commit 24457b4

Browse files
committed
[Compiler plugin] Support valueCounts operation
1 parent 3f054ab commit 24457b4

File tree

6 files changed

+62
-0
lines changed

6 files changed

+62
-0
lines changed

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/valueCounts.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import org.jetbrains.kotlinx.dataframe.ColumnsSelector
55
import org.jetbrains.kotlinx.dataframe.DataColumn
66
import org.jetbrains.kotlinx.dataframe.DataFrame
77
import org.jetbrains.kotlinx.dataframe.annotations.DataSchema
8+
import org.jetbrains.kotlinx.dataframe.annotations.Interpretable
9+
import org.jetbrains.kotlinx.dataframe.annotations.Refine
810
import org.jetbrains.kotlinx.dataframe.columns.toColumnSet
911
import org.jetbrains.kotlinx.dataframe.impl.nameGenerator
1012
import kotlin.reflect.KProperty
@@ -50,6 +52,8 @@ public fun <T> DataColumn<T>.valueCounts(
5052

5153
// region DataFrame
5254

55+
@Refine
56+
@Interpretable("ValueCounts")
5357
public fun <T> DataFrame<T>.valueCounts(
5458
sort: Boolean = true,
5559
ascending: Boolean = false,

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/impl/ExpectedArgumentDelegates.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,8 @@ internal fun <T> AbstractInterpreter<T>.dsl(
7878
): ExpectedArgumentProvider<(Any, Map<String, Interpreter.Success<Any?>>) -> Unit> =
7979
arg(name, lens = Interpreter.Dsl, defaultValue = Present(value = {_, _ -> }))
8080

81+
internal fun <T> AbstractInterpreter<T>.ignore(
82+
name: ArgumentName? = null
83+
): ExpectedArgumentProvider<Nothing?> =
84+
arg(name, lens = Interpreter.Id, defaultValue = Present(null))
85+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
2+
3+
package org.jetbrains.kotlinx.dataframe.plugin.impl.api
4+
5+
import org.jetbrains.kotlinx.dataframe.api.ValueCount
6+
import org.jetbrains.kotlinx.dataframe.plugin.extensions.wrap
7+
import org.jetbrains.kotlinx.dataframe.plugin.impl.AbstractSchemaModificationInterpreter
8+
import org.jetbrains.kotlinx.dataframe.plugin.impl.Arguments
9+
import org.jetbrains.kotlinx.dataframe.plugin.impl.PluginDataFrameSchema
10+
import org.jetbrains.kotlinx.dataframe.plugin.impl.Present
11+
import org.jetbrains.kotlinx.dataframe.plugin.impl.SimpleDataColumn
12+
import org.jetbrains.kotlinx.dataframe.plugin.impl.dataFrame
13+
import org.jetbrains.kotlinx.dataframe.plugin.impl.ignore
14+
15+
class ValueCounts : AbstractSchemaModificationInterpreter() {
16+
val Arguments.receiver by dataFrame()
17+
val Arguments.dropNA by ignore()
18+
val Arguments.ascending by ignore()
19+
val Arguments.sort by ignore()
20+
val Arguments.resultColumn: String by arg(defaultValue = Present(ValueCount::count.name))
21+
val Arguments.columns: ColumnsResolver? by arg(defaultValue = Present(null))
22+
23+
override fun Arguments.interpret(): PluginDataFrameSchema {
24+
val res = columns?.resolve(receiver)?.map { it.column } ?: receiver.columns()
25+
val generator = org.jetbrains.kotlinx.dataframe.impl.ColumnNameGenerator(res.map { it.name })
26+
val count = SimpleDataColumn(generator.addUnique(resultColumn), session.builtinTypes.intType.type.wrap())
27+
return PluginDataFrameSchema(res + count)
28+
}
29+
}

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/loadInterpreter.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ import org.jetbrains.kotlinx.dataframe.plugin.impl.api.ToTop
100100
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.TrimMargin
101101
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.Update0
102102
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.UpdateWith0
103+
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.ValueCounts
103104
import org.jetbrains.kotlinx.dataframe.plugin.utils.Names
104105

105106
internal fun FirFunctionCall.loadInterpreter(session: FirSession): Interpreter<*>? {
@@ -248,6 +249,7 @@ internal inline fun <reified T> String.load(): T {
248249
"Update0" -> Update0()
249250
"Aggregate" -> Aggregate()
250251
"DataFrameOf3" -> DataFrameOf3()
252+
"ValueCounts" -> ValueCounts()
251253
else -> error("$this")
252254
} as T
253255
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import org.jetbrains.kotlinx.dataframe.*
2+
import org.jetbrains.kotlinx.dataframe.annotations.*
3+
import org.jetbrains.kotlinx.dataframe.api.*
4+
import org.jetbrains.kotlinx.dataframe.io.*
5+
6+
fun box(): String {
7+
val df = dataFrameOf("a" to listOf("1", "1", "2", "3", "1", "4", "1"))
8+
val counts = df.valueCounts(ascending = true, sort = false, dropNA = false) { a }
9+
counts.a
10+
counts.count
11+
12+
val counts1 = df.valueCounts(resultColumn = "a") { a }
13+
val col: DataColumn<String> = counts1.a
14+
val col1: DataColumn<Int> counts1.a1
15+
return "OK"
16+
}

plugins/kotlin-dataframe/tests-gen/org/jetbrains/kotlin/fir/dataframe/DataFrameBlackBoxCodegenTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,12 @@ public void testUpdate() {
514514
runTest("testData/box/update.kt");
515515
}
516516

517+
@Test
518+
@TestMetadata("valueCounts.kt")
519+
public void testValueCounts() {
520+
runTest("testData/box/valueCounts.kt");
521+
}
522+
517523
@Test
518524
@TestMetadata("wrongReceiver.kt")
519525
public void testWrongReceiver() {

0 commit comments

Comments
 (0)