Skip to content

Commit 1d50a15

Browse files
committed
tiny fix for sum and null-filled columns
1 parent 0aa4038 commit 1d50a15

File tree

2 files changed

+45
-4
lines changed
  • core/src
    • main/kotlin/org/jetbrains/kotlinx/dataframe/impl
    • test/kotlin/org/jetbrains/kotlinx/dataframe/statistics

2 files changed

+45
-4
lines changed

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/NumberTypeUtils.kt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import java.math.BigDecimal
66
import java.math.BigInteger
77
import kotlin.reflect.KClass
88
import kotlin.reflect.KType
9+
import kotlin.reflect.full.isSubtypeOf
910
import kotlin.reflect.full.withNullability
1011
import kotlin.reflect.typeOf
1112

@@ -224,10 +225,24 @@ internal fun Sequence<Number?>.convertToUnifiedNumberType(
224225
"Cannot find unified number type of types: ${types.joinToString { renderType(it) }}",
225226
)
226227
}
227-
val converter = createConverter(typeOf<Number>(), commonNumberType)!! as (Number) -> Number?
228-
return map {
229-
if (it == null) return@map null
230-
converter(it) ?: error("Can not convert $it to $commonNumberType")
228+
require(commonNumberType.isSubtypeOf(typeOf<Number?>())) {
229+
"Cannot convert numbers to $commonNumberType; it is not a subtype of Number?"
230+
}
231+
return when (commonNumberType) {
232+
nothingType -> {
233+
require(null !in this) { "Cannot unify numbers to Nothing; it contains nulls" }
234+
this
235+
}
236+
237+
nullableNothingType -> this
238+
239+
else -> {
240+
val converter = createConverter(typeOf<Number>(), commonNumberType)!! as (Number) -> Number?
241+
this.map {
242+
if (it == null) return@map null
243+
converter(it) ?: error("Can not convert $it to $commonNumberType")
244+
}
245+
}
231246
}
232247
}
233248

core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/statistics/sum.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import io.kotest.matchers.doubles.shouldBeNaN
55
import io.kotest.matchers.floats.shouldBeNaN
66
import io.kotest.matchers.shouldBe
77
import io.kotest.matchers.string.shouldContain
8+
import org.jetbrains.kotlinx.dataframe.DataColumn
9+
import org.jetbrains.kotlinx.dataframe.api.cast
810
import org.jetbrains.kotlinx.dataframe.api.columnOf
911
import org.jetbrains.kotlinx.dataframe.api.dataFrameOf
1012
import org.jetbrains.kotlinx.dataframe.api.isEmpty
@@ -14,7 +16,9 @@ import org.jetbrains.kotlinx.dataframe.api.sum
1416
import org.jetbrains.kotlinx.dataframe.api.sumFor
1517
import org.jetbrains.kotlinx.dataframe.api.sumOf
1618
import org.jetbrains.kotlinx.dataframe.api.toDataFrame
19+
import org.jetbrains.kotlinx.dataframe.impl.nullableNothingType
1720
import org.junit.Test
21+
import kotlin.reflect.typeOf
1822

1923
class SumTests {
2024

@@ -46,6 +50,28 @@ class SumTests {
4650
df.sumOf { value() } shouldBe expected
4751
}
4852

53+
@Test
54+
fun `empty column with types`() {
55+
val emptyIntCol by columnOf<Int?>(null, null)
56+
emptyIntCol.sum() shouldBe 0
57+
58+
// empty column with Number type
59+
val emptyNumberColumn = DataColumn.createValueColumn<Number?>(
60+
"emptyNumberColumn",
61+
listOf(null, null),
62+
typeOf<Number?>(),
63+
)
64+
emptyNumberColumn.sum() shouldBe 0.0
65+
66+
// empty column with nullable Nothing type
67+
val emptyNothingColumn = DataColumn.createValueColumn(
68+
"emptyNothingColumn",
69+
listOf(null, null),
70+
nullableNothingType,
71+
)
72+
emptyNothingColumn.cast<Number?>().sum() shouldBe 0.0
73+
}
74+
4975
@Test
5076
fun `test multiple columns`() {
5177
val value1 by columnOf(1, 2, 3)

0 commit comments

Comments
 (0)