Skip to content

Commit 77d46ae

Browse files
committed
Introduce transposeTo operation
1 parent ffe59ac commit 77d46ae

File tree

5 files changed

+37
-22
lines changed

5 files changed

+37
-22
lines changed

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package org.jetbrains.kotlinx.dataframe.api
22

33
import org.jetbrains.kotlinx.dataframe.AnyRow
44
import org.jetbrains.kotlinx.dataframe.Column
5+
import org.jetbrains.kotlinx.dataframe.ColumnsContainer
6+
import org.jetbrains.kotlinx.dataframe.DataColumn
57
import org.jetbrains.kotlinx.dataframe.DataFrame
68
import org.jetbrains.kotlinx.dataframe.DataRow
79
import org.jetbrains.kotlinx.dataframe.RowExpression
10+
import org.jetbrains.kotlinx.dataframe.annotations.DataSchema
811
import org.jetbrains.kotlinx.dataframe.columns.ColumnReference
912
import org.jetbrains.kotlinx.dataframe.impl.columnName
1013
import org.jetbrains.kotlinx.dataframe.impl.owner
@@ -21,8 +24,21 @@ public fun AnyRow.isNotEmpty(): Boolean = !isEmpty()
2124

2225
public inline fun <reified R> AnyRow.valuesOf(): List<R> = values().filterIsInstance<R>()
2326

27+
@DataSchema
2428
public data class NameValuePair<V>(val name: String, val value: V)
2529

30+
public val <V> ColumnsContainer<NameValuePair<V>>.name: DataColumn<String> @JvmName("NameValuePair_name") get() = this["name"] as DataColumn<String>
31+
public val <V> DataRow<NameValuePair<V>>.name: String @JvmName("NameValuePair_name") get() = this["name"] as String
32+
public val <V> ColumnsContainer<NameValuePair<V>>.value: DataColumn<V> @JvmName("NameValuePair_value") get() = this["value"] as DataColumn<V>
33+
public val <V> DataRow<NameValuePair<V>>.value: V @JvmName("NameValuePair_value") get() = this["value"] as V
34+
35+
// Without these overloads row.transpose().name or row.map { name } won't resolve
36+
public val ColumnsContainer<NameValuePair<*>>.name: DataColumn<String> @JvmName("NameValuePairAny_name") get() = this["name"] as DataColumn<String>
37+
public val DataRow<NameValuePair<*>>.name: String @JvmName("NameValuePairAny_name") get() = this["name"] as String
38+
39+
public val ColumnsContainer<NameValuePair<*>>.value: DataColumn<*> @JvmName("NameValuePairAny_value") get() = this["value"]
40+
public val DataRow<NameValuePair<*>>.value: Any? @JvmName("NameValuePairAny_value") get() = this["value"]
41+
2642
public inline fun <reified R> AnyRow.namedValuesOf(): List<NameValuePair<R>> =
2743
values().zip(columnNames()).filter { it.first is R }.map { NameValuePair(it.second, it.first as R) }
2844

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,21 @@
11
package org.jetbrains.kotlinx.dataframe.api
22

33
import org.jetbrains.kotlinx.dataframe.*
4-
import org.jetbrains.kotlinx.dataframe.annotations.DataSchema
4+
import org.jetbrains.kotlinx.dataframe.impl.api.convertTo
55
import org.jetbrains.kotlinx.dataframe.impl.columnName
66
import org.jetbrains.kotlinx.dataframe.impl.owner
77
import org.jetbrains.kotlinx.dataframe.values
8+
import kotlin.reflect.KType
9+
import kotlin.reflect.typeOf
810

911
// region DataRow
1012

11-
@DataSchema
12-
public interface NameValueSchema {
13-
public val name: String
14-
public val value: Any?
15-
}
16-
17-
public val DataRow<NameValueSchema>.name: String get() = this["name"] as String
18-
public val ColumnsContainer<NameValueSchema>.name: DataColumn<String> get() = this["name"] as DataColumn<String>
19-
public val DataRow<NameValueSchema>.value: Any? get() = this["value"]
20-
public val ColumnsContainer<NameValueSchema>.value: DataColumn<Any?> get() = this["value"]
21-
22-
public fun <T> DataRow<T>.transpose(): DataFrame<NameValueSchema> {
23-
val valueColumn = DataColumn.createWithTypeInference(NameValueSchema::value.columnName, values)
24-
val nameColumn = owner.columnNames().toValueColumn(NameValuePair<T>::name)
13+
public fun <T> DataRow<T>.transpose(): DataFrame<NameValuePair<*>> {
14+
val valueColumn = DataColumn.createWithTypeInference(NameValuePair<*>::value.columnName, values)
15+
val nameColumn = owner.columnNames().toValueColumn(NameValuePair<*>::name)
2516
return dataFrameOf(nameColumn, valueColumn).cast()
2617
}
2718

28-
/*
29-
3019
public inline fun <reified T> AnyRow.transposeTo(): DataFrame<NameValuePair<T>> = transposeTo(typeOf<T>())
3120

3221
@PublishedApi
@@ -37,6 +26,4 @@ internal fun <T> AnyRow.transposeTo(type: KType): DataFrame<NameValuePair<T>> {
3726
return dataFrameOf(nameColumn, valueColumn).cast()
3827
}
3928

40-
*/
41-
4229
// endregion

core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/puzzles/MediumTests.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,8 @@ class MediumTests {
4949
fun `smallest sum`() {
5050
val names = ('a'..'j').map { it.toString() }
5151
val df = dataFrameOf(names) { List(5) { random.nextDouble() } }
52-
val value by column<Double>()
53-
val name by column<String>()
5452

55-
df.sum().transpose().minBy { value() }[name] shouldBe "b"
53+
df.sum().transposeTo<Double>().minBy { value }.name shouldBe "b"
5654
df.sum().transpose().minBy("value")["name"] shouldBe "b"
5755
}
5856

core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/testSets/person/DataRowTests.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import io.kotest.matchers.shouldBe
44
import org.jetbrains.kotlinx.dataframe.api.by
55
import org.jetbrains.kotlinx.dataframe.api.columnNames
66
import org.jetbrains.kotlinx.dataframe.api.convert
7+
import org.jetbrains.kotlinx.dataframe.api.dataFrameOf
78
import org.jetbrains.kotlinx.dataframe.api.diff
89
import org.jetbrains.kotlinx.dataframe.api.drop
910
import org.jetbrains.kotlinx.dataframe.api.dropLast
11+
import org.jetbrains.kotlinx.dataframe.api.first
1012
import org.jetbrains.kotlinx.dataframe.api.intoList
1113
import org.jetbrains.kotlinx.dataframe.api.mapToColumn
1214
import org.jetbrains.kotlinx.dataframe.api.merge
15+
import org.jetbrains.kotlinx.dataframe.api.name
1316
import org.jetbrains.kotlinx.dataframe.api.namedValues
1417
import org.jetbrains.kotlinx.dataframe.api.namedValuesOf
1518
import org.jetbrains.kotlinx.dataframe.api.next
@@ -19,7 +22,9 @@ import org.jetbrains.kotlinx.dataframe.api.rowMean
1922
import org.jetbrains.kotlinx.dataframe.api.rowStd
2023
import org.jetbrains.kotlinx.dataframe.api.rowSum
2124
import org.jetbrains.kotlinx.dataframe.api.toDouble
25+
import org.jetbrains.kotlinx.dataframe.api.transposeTo
2226
import org.jetbrains.kotlinx.dataframe.api.update
27+
import org.jetbrains.kotlinx.dataframe.api.value
2328
import org.jetbrains.kotlinx.dataframe.api.valuesOf
2429
import org.jetbrains.kotlinx.dataframe.api.with
2530
import org.junit.Test
@@ -87,6 +92,13 @@ class DataRowTests : BaseTest() {
8792
}
8893
}
8994

95+
@Test
96+
fun transposeTo() {
97+
val df = dataFrameOf("a", "b")(1, 2).first().transposeTo<Int>()
98+
df.name.toList() shouldBe listOf("a", "b")
99+
df.value.toList() shouldBe listOf(1, 2)
100+
}
101+
90102
@Test
91103
fun relativeTest() {
92104
typed[1].relative(0..0) shouldBe typed[1..1]

docs/StardustDocs/topics/DataRow.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
* `columnTypes(): List<KType>` — list of all column types
1717
* `namedValues(): List<NameValuePair<Any?>>` — list of name-value pairs where `name` is a column name and `value` is cell value
1818
* `namedValuesOf<T>(): List<NameValuePair<T>>` — list of name-value pairs where value has given type
19+
* `transpose(): DataFrame<NameValuePair<*>>` — dataframe of two columns: `name: String` is column names and `value: Any?` is cell values
20+
* `transposeTo<T>(): DataFrame<NameValuePair<T>>`— dataframe of two columns: `name: String` is column names and `value: T` is cell values
1921
* `getRow(Int): DataRow` — row from `DataFrame` by row index
2022
* `getRows(Iterable<Int>): DataFrame` — dataframe with subset of rows selected by absolute row index.
2123
* `relative(Iterable<Int>): DataFrame` — dataframe with subset of rows selected by relative row index: `relative(-1..1)` will return previous, current and next row. Requested indices will be coerced to the valid range and invalid indices will be skipped

0 commit comments

Comments
 (0)