Skip to content

Commit 1c95cf4

Browse files
authored
Merge pull request #205 from Kotlin/npe-update-not-null-prop
Bugfix for NPE with fillNulls
2 parents b59cfb6 + 951731c commit 1c95cf4

File tree

2 files changed

+114
-38
lines changed
  • core/src
    • main/kotlin/org/jetbrains/kotlinx/dataframe/api
    • test/kotlin/org/jetbrains/kotlinx/dataframe/api

2 files changed

+114
-38
lines changed

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

Lines changed: 85 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,34 @@ import kotlin.reflect.KProperty
1717

1818
// region fillNulls
1919

20-
public fun <T, C> DataFrame<T>.fillNulls(cols: ColumnsSelector<T, C>): Update<T, C> = update(cols).where { it == null }
21-
public fun <T> DataFrame<T>.fillNulls(vararg cols: String): Update<T, Any?> = fillNulls { cols.toColumns() }
22-
public fun <T, C> DataFrame<T>.fillNulls(vararg cols: KProperty<C>): Update<T, C> = fillNulls { cols.toColumns() }
23-
public fun <T, C> DataFrame<T>.fillNulls(vararg cols: ColumnReference<C>): Update<T, C> = fillNulls { cols.toColumns() }
24-
public fun <T, C> DataFrame<T>.fillNulls(cols: Iterable<ColumnReference<C>>): Update<T, C> = fillNulls { cols.toColumnSet() }
20+
public fun <T, C> DataFrame<T>.fillNulls(cols: ColumnsSelector<T, C?>): Update<T, C?> =
21+
update(cols).where { it == null }
22+
23+
public fun <T> DataFrame<T>.fillNulls(vararg cols: String): Update<T, Any?> =
24+
fillNulls { cols.toColumns() }
25+
26+
public fun <T, C> DataFrame<T>.fillNulls(vararg cols: KProperty<C>): Update<T, C?> =
27+
fillNulls { cols.toColumns() }
28+
29+
public fun <T, C> DataFrame<T>.fillNulls(vararg cols: ColumnReference<C>): Update<T, C?> =
30+
fillNulls { cols.toColumns() }
31+
32+
public fun <T, C> DataFrame<T>.fillNulls(cols: Iterable<ColumnReference<C>>): Update<T, C?> =
33+
fillNulls { cols.toColumnSet() }
2534

2635
// endregion
2736

2837
internal inline val Any?.isNaN: Boolean get() = (this is Double && isNaN()) || (this is Float && isNaN())
2938

30-
internal inline val Any?.isNA: Boolean get() = when (this) {
31-
null -> true
32-
is Double -> isNaN()
33-
is Float -> isNaN()
34-
is AnyRow -> allNA()
35-
is AnyFrame -> isEmpty()
36-
else -> false
37-
}
39+
internal inline val Any?.isNA: Boolean
40+
get() = when (this) {
41+
null -> true
42+
is Double -> isNaN()
43+
is Float -> isNaN()
44+
is AnyRow -> allNA()
45+
is AnyFrame -> isEmpty()
46+
else -> false
47+
}
3848

3949
internal inline val AnyCol.canHaveNaN: Boolean get() = typeClass.let { it == Double::class || it == Float::class }
4050

@@ -46,21 +56,39 @@ internal inline val Float?.isNA: Boolean get() = this == null || this.isNaN()
4656

4757
// region fillNaNs
4858

49-
public fun <T, C> DataFrame<T>.fillNaNs(cols: ColumnsSelector<T, C>): Update<T, C> = update(cols).where { it.isNaN }
50-
public fun <T> DataFrame<T>.fillNaNs(vararg cols: String): Update<T, Any?> = fillNaNs { cols.toColumns() }
51-
public fun <T, C> DataFrame<T>.fillNaNs(vararg cols: KProperty<C>): Update<T, C> = fillNaNs { cols.toColumns() }
52-
public fun <T, C> DataFrame<T>.fillNaNs(vararg cols: ColumnReference<C>): Update<T, C> = fillNaNs { cols.toColumns() }
53-
public fun <T, C> DataFrame<T>.fillNaNs(cols: Iterable<ColumnReference<C>>): Update<T, C> = fillNaNs { cols.toColumnSet() }
59+
public fun <T, C> DataFrame<T>.fillNaNs(cols: ColumnsSelector<T, C>): Update<T, C> =
60+
update(cols).where { it.isNaN }
61+
62+
public fun <T> DataFrame<T>.fillNaNs(vararg cols: String): Update<T, Any?> =
63+
fillNaNs { cols.toColumns() }
64+
65+
public fun <T, C> DataFrame<T>.fillNaNs(vararg cols: KProperty<C>): Update<T, C> =
66+
fillNaNs { cols.toColumns() }
67+
68+
public fun <T, C> DataFrame<T>.fillNaNs(vararg cols: ColumnReference<C>): Update<T, C> =
69+
fillNaNs { cols.toColumns() }
70+
71+
public fun <T, C> DataFrame<T>.fillNaNs(cols: Iterable<ColumnReference<C>>): Update<T, C> =
72+
fillNaNs { cols.toColumnSet() }
5473

5574
// endregion
5675

5776
// region fillNA
5877

59-
public fun <T, C> DataFrame<T>.fillNA(cols: ColumnsSelector<T, C>): Update<T, C> = update(cols).where { it.isNA }
60-
public fun <T> DataFrame<T>.fillNA(vararg cols: String): Update<T, Any?> = fillNA { cols.toColumns() }
61-
public fun <T, C> DataFrame<T>.fillNA(vararg cols: KProperty<C>): Update<T, C> = fillNA { cols.toColumns() }
62-
public fun <T, C> DataFrame<T>.fillNA(vararg cols: ColumnReference<C>): Update<T, C> = fillNA { cols.toColumns() }
63-
public fun <T, C> DataFrame<T>.fillNA(cols: Iterable<ColumnReference<C>>): Update<T, C> = fillNA { cols.toColumnSet() }
78+
public fun <T, C> DataFrame<T>.fillNA(cols: ColumnsSelector<T, C?>): Update<T, C?> =
79+
update(cols).where { it.isNA }
80+
81+
public fun <T> DataFrame<T>.fillNA(vararg cols: String): Update<T, Any?> =
82+
fillNA { cols.toColumns() }
83+
84+
public fun <T, C> DataFrame<T>.fillNA(vararg cols: KProperty<C>): Update<T, C?> =
85+
fillNA { cols.toColumns() }
86+
87+
public fun <T, C> DataFrame<T>.fillNA(vararg cols: ColumnReference<C>): Update<T, C?> =
88+
fillNA { cols.toColumns() }
89+
90+
public fun <T, C> DataFrame<T>.fillNA(cols: Iterable<ColumnReference<C>>): Update<T, C?> =
91+
fillNA { cols.toColumnSet() }
6492

6593
// endregion
6694

@@ -72,13 +100,23 @@ public fun <T> DataFrame<T>.dropNulls(whereAllNull: Boolean = false, selector: C
72100
else drop { row -> cols.any { col -> col[row] == null } }
73101
}
74102

75-
public fun <T> DataFrame<T>.dropNulls(whereAllNull: Boolean = false): DataFrame<T> = dropNulls(whereAllNull) { all() }
76-
public fun <T> DataFrame<T>.dropNulls(vararg cols: KProperty<*>, whereAllNull: Boolean = false): DataFrame<T> = dropNulls(whereAllNull) { cols.toColumns() }
77-
public fun <T> DataFrame<T>.dropNulls(vararg cols: String, whereAllNull: Boolean = false): DataFrame<T> = dropNulls(whereAllNull) { cols.toColumns() }
78-
public fun <T> DataFrame<T>.dropNulls(vararg cols: Column, whereAllNull: Boolean = false): DataFrame<T> = dropNulls(whereAllNull) { cols.toColumns() }
79-
public fun <T> DataFrame<T>.dropNulls(cols: Iterable<Column>, whereAllNull: Boolean = false): DataFrame<T> = dropNulls(whereAllNull) { cols.toColumnSet() }
103+
public fun <T> DataFrame<T>.dropNulls(whereAllNull: Boolean = false): DataFrame<T> =
104+
dropNulls(whereAllNull) { all() }
105+
106+
public fun <T> DataFrame<T>.dropNulls(vararg cols: KProperty<*>, whereAllNull: Boolean = false): DataFrame<T> =
107+
dropNulls(whereAllNull) { cols.toColumns() }
108+
109+
public fun <T> DataFrame<T>.dropNulls(vararg cols: String, whereAllNull: Boolean = false): DataFrame<T> =
110+
dropNulls(whereAllNull) { cols.toColumns() }
111+
112+
public fun <T> DataFrame<T>.dropNulls(vararg cols: Column, whereAllNull: Boolean = false): DataFrame<T> =
113+
dropNulls(whereAllNull) { cols.toColumns() }
80114

81-
public fun <T> DataColumn<T?>.dropNulls(): DataColumn<T> = (if (!hasNulls()) this else filter { it != null }) as DataColumn<T>
115+
public fun <T> DataFrame<T>.dropNulls(cols: Iterable<Column>, whereAllNull: Boolean = false): DataFrame<T> =
116+
dropNulls(whereAllNull) { cols.toColumnSet() }
117+
118+
public fun <T> DataColumn<T?>.dropNulls(): DataColumn<T> =
119+
(if (!hasNulls()) this else filter { it != null }) as DataColumn<T>
82120

83121
// endregion
84122

@@ -91,16 +129,25 @@ public fun <T> DataFrame<T>.dropNA(whereAllNA: Boolean = false, selector: Column
91129
else drop { cols.any { this[it].isNA } }
92130
}
93131

94-
public fun <T> DataFrame<T>.dropNA(vararg cols: KProperty<*>, whereAllNA: Boolean = false): DataFrame<T> = dropNA(whereAllNA) { cols.toColumns() }
95-
public fun <T> DataFrame<T>.dropNA(vararg cols: String, whereAllNA: Boolean = false): DataFrame<T> = dropNA(whereAllNA) { cols.toColumns() }
96-
public fun <T> DataFrame<T>.dropNA(vararg cols: Column, whereAllNA: Boolean = false): DataFrame<T> = dropNA(whereAllNA) { cols.toColumns() }
97-
public fun <T> DataFrame<T>.dropNA(cols: Iterable<Column>, whereAllNA: Boolean = false): DataFrame<T> = dropNA(whereAllNA) { cols.toColumnSet() }
132+
public fun <T> DataFrame<T>.dropNA(vararg cols: KProperty<*>, whereAllNA: Boolean = false): DataFrame<T> =
133+
dropNA(whereAllNA) { cols.toColumns() }
98134

99-
public fun <T> DataFrame<T>.dropNA(whereAllNA: Boolean = false): DataFrame<T> = dropNA(whereAllNA) { all() }
135+
public fun <T> DataFrame<T>.dropNA(vararg cols: String, whereAllNA: Boolean = false): DataFrame<T> =
136+
dropNA(whereAllNA) { cols.toColumns() }
100137

101-
public fun <T> DataColumn<T?>.dropNA(): DataColumn<T> = when (typeClass) {
102-
Double::class, Float::class -> filter { !it.isNA }.cast()
103-
else -> (if (!hasNulls()) this else filter { it != null }) as DataColumn<T>
104-
}
138+
public fun <T> DataFrame<T>.dropNA(vararg cols: Column, whereAllNA: Boolean = false): DataFrame<T> =
139+
dropNA(whereAllNA) { cols.toColumns() }
140+
141+
public fun <T> DataFrame<T>.dropNA(cols: Iterable<Column>, whereAllNA: Boolean = false): DataFrame<T> =
142+
dropNA(whereAllNA) { cols.toColumnSet() }
143+
144+
public fun <T> DataFrame<T>.dropNA(whereAllNA: Boolean = false): DataFrame<T> =
145+
dropNA(whereAllNA) { all() }
146+
147+
public fun <T> DataColumn<T?>.dropNA(): DataColumn<T> =
148+
when (typeClass) {
149+
Double::class, Float::class -> filter { !it.isNA }.cast()
150+
else -> (if (!hasNulls()) this else filter { it != null }) as DataColumn<T>
151+
}
105152

106153
// endregion

core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api/update.kt

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

33
import io.kotest.matchers.shouldBe
44
import org.jetbrains.kotlinx.dataframe.DataFrame
5+
import org.jetbrains.kotlinx.dataframe.annotations.DataSchema
56
import org.junit.Test
67

78
class UpdateTests {
@@ -12,4 +13,32 @@ class UpdateTests {
1213
val col by column<Int>()
1314
df.update { col }.with { 2 } shouldBe df
1415
}
16+
17+
@DataSchema
18+
interface SchemaA {
19+
val i: Int?
20+
}
21+
22+
@DataSchema
23+
interface SchemaB {
24+
val i: Int
25+
}
26+
27+
@Test
28+
fun `fillNulls update`() {
29+
val df = dataFrameOf("i")(1, null)
30+
31+
df.fillNulls(SchemaA::i).with { 42 }
32+
33+
df.fillNulls(SchemaB::i).with { 42 }
34+
}
35+
36+
@Test
37+
fun `fillNA update`() {
38+
val df = dataFrameOf("i")(1, null)
39+
40+
df.fillNA(SchemaA::i).with { 42 }
41+
42+
df.fillNA(SchemaB::i).with { 42 }
43+
}
1544
}

0 commit comments

Comments
 (0)