Skip to content

Commit b8e90f8

Browse files
Automated commit of generated code
1 parent 5449da2 commit b8e90f8

File tree

3 files changed

+318
-4
lines changed
  • core/generated-sources/src

3 files changed

+318
-4
lines changed

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/explode.kt

Lines changed: 226 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,117 @@ private val defaultExplodeColumns: ColumnsSelector<*, *> = {
1919
}
2020

2121
// region explode DataFrame
22+
23+
/**
24+
* Splits list-like values in the specified [columns] and spreads them vertically —
25+
* that is, it adds a separate row for each element (one value per row).
26+
* Values in all other columns are duplicated to preserve row context.
27+
*
28+
* If no [columns] are specified, all columns (at any depth) containing
29+
* [List] or [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame] values will be exploded.
30+
*
31+
* If [dropEmpty] is `true`, rows with empty lists or [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame]s will be removed.
32+
* If `false`, such rows will be exploded into `null` values.
33+
*
34+
* Returns a new [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame] with exploded columns.
35+
*
36+
* Each exploded column will have a new type (`List<T>` -> `T`).
37+
* When several columns are exploded in one operation, lists in different columns will be aligned.
38+
*
39+
* This operation is the reverse of [implode][org.jetbrains.kotlinx.dataframe.api.implode].
40+
*
41+
* This can include [column groups][org.jetbrains.kotlinx.dataframe.columns.ColumnGroup] and nested columns.
42+
*
43+
* For more information, see: [See `explode` on the documentation website.](https://kotlin.github.io/dataframe/explode.html)
44+
*
45+
* ### This `explode` overload
46+
* Select or express columns using the [Columns Selection DSL][org.jetbrains.kotlinx.dataframe.api.ColumnsSelectionDsl].
47+
* (Any (combination of) [Access API][org.jetbrains.kotlinx.dataframe.documentation.AccessApi]).
48+
*
49+
* This DSL is initiated by a [Columns Selector][org.jetbrains.kotlinx.dataframe.ColumnsSelector] lambda,
50+
* which operates in the context of the [Columns Selection DSL][org.jetbrains.kotlinx.dataframe.api.ColumnsSelectionDsl] and
51+
* expects you to return a [SingleColumn][org.jetbrains.kotlinx.dataframe.columns.SingleColumn] or [ColumnSet][org.jetbrains.kotlinx.dataframe.columns.ColumnSet] (so, a [ColumnsResolver][org.jetbrains.kotlinx.dataframe.columns.ColumnsResolver]).
52+
* This is an entity formed by calling any (combination) of the functions
53+
* in the DSL that is or can be resolved into one or more columns.
54+
*
55+
* #### NOTE:
56+
* While you can use the [String API][org.jetbrains.kotlinx.dataframe.documentation.AccessApi.StringApi] and [KProperties API][org.jetbrains.kotlinx.dataframe.documentation.AccessApi.KPropertiesApi]
57+
* in this DSL directly with any function, they are NOT valid return types for the
58+
* [Columns Selector][org.jetbrains.kotlinx.dataframe.ColumnsSelector] lambda. You'd need to turn them into a [ColumnReference][org.jetbrains.kotlinx.dataframe.columns.ColumnReference] first, for instance
59+
* with a function like [`col("name")`][org.jetbrains.kotlinx.dataframe.api.ColumnsSelectionDsl.col].
60+
*
61+
* ### Check out: [Columns Selection DSL Grammar][org.jetbrains.kotlinx.dataframe.api.ColumnsSelectionDsl.DslGrammar]
62+
*
63+
* &nbsp;&nbsp;&nbsp;&nbsp;
64+
*
65+
* [See Column Selectors on the documentation website.](https://kotlin.github.io/dataframe/columnselectors.html)
66+
*
67+
* #### Examples
68+
*
69+
* ```kotlin
70+
* // Explodes all `List` and `DataFrame` columns at any depth
71+
* df.explode()
72+
*
73+
* // Explodes the "tags" column of type `List<String>`
74+
* df.explode { tags }
75+
*
76+
* // Explodes all columns of type `List<Double>`
77+
* df.explode { colsOf<List<Double>>() }
78+
* ```
79+
*
80+
* @param dropEmpty If `true`, removes rows with empty lists or DataFrames.
81+
* If `false`, such rows will be exploded into `null` values.
82+
* @param columns The [ColumnsSelector] used to select columns to explode.
83+
* If not specified, all applicable columns will be exploded.
84+
* @return A new [DataFrame] with exploded columns.
85+
*/
2286
@Refine
2387
@Interpretable("Explode0")
2488
public fun <T> DataFrame<T>.explode(
2589
dropEmpty: Boolean = true,
26-
selector: ColumnsSelector<T, *> = defaultExplodeColumns,
27-
): DataFrame<T> = explodeImpl(dropEmpty, selector)
90+
columns: ColumnsSelector<T, *> = defaultExplodeColumns,
91+
): DataFrame<T> = explodeImpl(dropEmpty, columns)
2892

93+
/**
94+
* Splits list-like values in the specified [columns] and spreads them vertically —
95+
* that is, it adds a separate row for each element (one value per row).
96+
* Values in all other columns are duplicated to preserve row context.
97+
*
98+
* If no [columns] are specified, all columns (at any depth) containing
99+
* [List] or [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame] values will be exploded.
100+
*
101+
* If [dropEmpty] is `true`, rows with empty lists or [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame]s will be removed.
102+
* If `false`, such rows will be exploded into `null` values.
103+
*
104+
* Returns a new [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame] with exploded columns.
105+
*
106+
* Each exploded column will have a new type (`List<T>` -> `T`).
107+
* When several columns are exploded in one operation, lists in different columns will be aligned.
108+
*
109+
* This operation is the reverse of [implode][org.jetbrains.kotlinx.dataframe.api.implode].
110+
*
111+
* This can include [column groups][org.jetbrains.kotlinx.dataframe.columns.ColumnGroup] and nested columns.
112+
*
113+
* For more information, see: [See `explode` on the documentation website.](https://kotlin.github.io/dataframe/explode.html)
114+
*
115+
* ### This `explode` overload
116+
* Select columns using their [column names][String]
117+
* ([String API][org.jetbrains.kotlinx.dataframe.documentation.AccessApi.StringApi]).
118+
*
119+
* #### Example
120+
*
121+
* ```kotlin
122+
* // Explodes the "tags" and "scores" columns, where
123+
* // "tags" is a `List<String>` and "scores" is a `List<Int>`
124+
* val exploded = df.explode("tags", "scores")
125+
* ```
126+
*
127+
* @param dropEmpty If `true`, removes rows with empty lists or DataFrames.
128+
* If `false`, such rows will be exploded into `null` values.
129+
* @param columns The [column names][String] used to select columns to explode.
130+
* If not specified, all applicable columns will be exploded.
131+
* @return A new [DataFrame] with exploded columns.
132+
*/
29133
public fun <T> DataFrame<T>.explode(vararg columns: String, dropEmpty: Boolean = true): DataFrame<T> =
30134
explode(dropEmpty) { columns.toColumnSet() }
31135

@@ -43,11 +147,107 @@ public fun <T, C> DataFrame<T>.explode(vararg columns: KProperty<C>, dropEmpty:
43147

44148
// region explode DataRow
45149

150+
/**
151+
* Splits list-like values in the specified [columns] of this [DataRow][org.jetbrains.kotlinx.dataframe.DataRow] and spreads them vertically —
152+
* that is, it adds a separate row for each element (one value per row)
153+
* and combine them into new [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame].
154+
* Values in all other columns are duplicated to preserve row context.
155+
*
156+
* If no [columns] are specified, all columns (at any depth) containing
157+
* [List] or [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame] values will be exploded.
158+
*
159+
* If [dropEmpty] is `true`, the result will exclude rows with empty lists or DataFrames.
160+
* If `false`, such values will be exploded into `null`.
161+
*
162+
* Returns a new [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame] expanded into multiple rows based on the exploded columns.
163+
*
164+
* Each exploded column will have a new type (`List<T>` → `T`).
165+
* When several columns are exploded in one operation, lists in different columns will be aligned.
166+
*
167+
* This can include [column groups][org.jetbrains.kotlinx.dataframe.columns.ColumnGroup] and nested columns.
168+
*
169+
* For more information, see: [See `explode` on the documentation website.](https://kotlin.github.io/dataframe/explode.html)
170+
*
171+
* ### This `explode` overload
172+
* Select or express columns using the [Columns Selection DSL][org.jetbrains.kotlinx.dataframe.api.ColumnsSelectionDsl].
173+
* (Any (combination of) [Access API][org.jetbrains.kotlinx.dataframe.documentation.AccessApi]).
174+
*
175+
* This DSL is initiated by a [Columns Selector][org.jetbrains.kotlinx.dataframe.ColumnsSelector] lambda,
176+
* which operates in the context of the [Columns Selection DSL][org.jetbrains.kotlinx.dataframe.api.ColumnsSelectionDsl] and
177+
* expects you to return a [SingleColumn][org.jetbrains.kotlinx.dataframe.columns.SingleColumn] or [ColumnSet][org.jetbrains.kotlinx.dataframe.columns.ColumnSet] (so, a [ColumnsResolver][org.jetbrains.kotlinx.dataframe.columns.ColumnsResolver]).
178+
* This is an entity formed by calling any (combination) of the functions
179+
* in the DSL that is or can be resolved into one or more columns.
180+
*
181+
* #### NOTE:
182+
* While you can use the [String API][org.jetbrains.kotlinx.dataframe.documentation.AccessApi.StringApi] and [KProperties API][org.jetbrains.kotlinx.dataframe.documentation.AccessApi.KPropertiesApi]
183+
* in this DSL directly with any function, they are NOT valid return types for the
184+
* [Columns Selector][org.jetbrains.kotlinx.dataframe.ColumnsSelector] lambda. You'd need to turn them into a [ColumnReference][org.jetbrains.kotlinx.dataframe.columns.ColumnReference] first, for instance
185+
* with a function like [`col("name")`][org.jetbrains.kotlinx.dataframe.api.ColumnsSelectionDsl.col].
186+
*
187+
* ### Check out: [Columns Selection DSL Grammar][org.jetbrains.kotlinx.dataframe.api.ColumnsSelectionDsl.DslGrammar]
188+
*
189+
* &nbsp;&nbsp;&nbsp;&nbsp;
190+
*
191+
* [See Column Selectors on the documentation website.](https://kotlin.github.io/dataframe/columnselectors.html)
192+
*
193+
* #### Example
194+
*
195+
* ```kotlin
196+
* // Explodes the `hobbies` and `scores` values of the row,
197+
* // of types `List<String>` and `List<Int>`, respectively
198+
* row.explode { hobbies and scores }
199+
* ```
200+
*
201+
* @param dropEmpty If `true`, removes rows with empty lists or DataFrames.
202+
* If `false`, such rows will be exploded into `null` values.
203+
* @param columns The [ColumnsSelector] used to select columns to explode.
204+
* If not specified, all applicable columns will be exploded.
205+
* @return A new [DataFrame] with exploded columns from this [DataRow].
206+
*/
46207
public fun <T> DataRow<T>.explode(
47208
dropEmpty: Boolean = true,
48-
selector: ColumnsSelector<T, *> = defaultExplodeColumns,
49-
): DataFrame<T> = toDataFrame().explode(dropEmpty, selector)
209+
columns: ColumnsSelector<T, *> = defaultExplodeColumns,
210+
): DataFrame<T> = toDataFrame().explode(dropEmpty, columns)
50211

212+
/**
213+
* Splits list-like values in the specified [columns] of this [DataRow][org.jetbrains.kotlinx.dataframe.DataRow] and spreads them vertically —
214+
* that is, it adds a separate row for each element (one value per row)
215+
* and combine them into new [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame].
216+
* Values in all other columns are duplicated to preserve row context.
217+
*
218+
* If no [columns] are specified, all columns (at any depth) containing
219+
* [List] or [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame] values will be exploded.
220+
*
221+
* If [dropEmpty] is `true`, the result will exclude rows with empty lists or DataFrames.
222+
* If `false`, such values will be exploded into `null`.
223+
*
224+
* Returns a new [DataFrame][org.jetbrains.kotlinx.dataframe.DataFrame] expanded into multiple rows based on the exploded columns.
225+
*
226+
* Each exploded column will have a new type (`List<T>` → `T`).
227+
* When several columns are exploded in one operation, lists in different columns will be aligned.
228+
*
229+
* This can include [column groups][org.jetbrains.kotlinx.dataframe.columns.ColumnGroup] and nested columns.
230+
*
231+
* For more information, see: [See `explode` on the documentation website.](https://kotlin.github.io/dataframe/explode.html)
232+
*
233+
* ### This `explode` overload
234+
* Select columns using their [column names][String]
235+
* ([String API][org.jetbrains.kotlinx.dataframe.documentation.AccessApi.StringApi]).
236+
*
237+
* #### Example
238+
*
239+
* ```kotlin
240+
* // Explodes the `hobbies` and `scores` values of the row,
241+
* // of types `List<String>` and `List<Int>`, respectively
242+
* row.explode("hobbies", "scores")
243+
* ```
244+
*
245+
* @param dropEmpty If `true`, removes rows with empty lists or DataFrames.
246+
* If `false`, such rows will be exploded into `null` values.
247+
* @param columns The [column names][String] used to select columns to explode.
248+
* If not specified, all applicable columns will be exploded.
249+
* @return A new [DataFrame] with exploded columns from this [DataRow].
250+
*/
51251
public fun <T> DataRow<T>.explode(vararg columns: String, dropEmpty: Boolean = true): DataFrame<T> =
52252
explode(dropEmpty) { columns.toColumnSet() }
53253

@@ -65,9 +265,31 @@ public fun <T, C> DataRow<T>.explode(vararg columns: KProperty<C>, dropEmpty: Bo
65265

66266
// region explode DataColumn
67267

268+
/**
269+
* Splits list-like values in this [DataColumn] and spreads them vertically —
270+
* that is, it adds a separate row for each element (one value per row).
271+
*
272+
* Returns a new [DataColumn] with the exploded values.
273+
* The resulting column will have a new type (`List<T>` → `T`).
274+
*
275+
* For more information, see: [See `explode` on the documentation website.](https://kotlin.github.io/dataframe/explode.html)
276+
*
277+
* @return A new [DataColumn] with exploded values.
278+
*/
68279
@JvmName("explodeList")
69280
public fun <T> DataColumn<Collection<T>>.explode(): DataColumn<T> = explodeImpl() as DataColumn<T>
70281

282+
/**
283+
* Explodes a [DataColumn] of [DataFrame] values into a single [ColumnGroup].
284+
*
285+
* Each nested [DataFrame] is unwrapped, and its columns are placed side by side
286+
* within a column group named after the original column.
287+
* The number of resulting rows equals the total number of rows across all nested DataFrames.
288+
*
289+
* For more information, see: [See `explode` on the documentation website.](https://kotlin.github.io/dataframe/explode.html)
290+
*
291+
* @return A [ColumnGroup] containing the concatenated contents of all nested DataFrames.
292+
*/
71293
@JvmName("explodeFrames")
72294
public fun <T> DataColumn<DataFrame<T>>.explode(): ColumnGroup<T> = concat().asColumnGroup(name())
73295

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/gather.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ public fun <T, C, K, R> Gather<T, C?, K, R>.notNull(): Gather<T, C, K, R> = wher
328328
* .mapValues { (it + 0.5).toFloat() }
329329
* .into("series", "value")
330330
* ```
331+
*
332+
* @see [explode]
331333
* @return A new [Gather] instance with exploded list values.
332334
*/
333335
@Interpretable("GatherExplodeLists")
@@ -365,6 +367,8 @@ public fun <T, C, K, R> Gather<T, C, K, R>.explodeLists(): Gather<T, C, K, R> =
365367
* .mapValues { (it + 0.5).toFloat() }
366368
* .into("series", "value")
367369
* ```
370+
*
371+
* @see [explode]
368372
* @return A new [Gather] instance with exploded list values.
369373
*/
370374
@JvmName("explodeListsTyped")

core/generated-sources/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api/explode.kt

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,92 @@ class ExplodeTests {
4444
val df = dataFrameOf("a", "b")(1, 2)
4545
df.explode() shouldBe df
4646
}
47+
48+
@Test
49+
fun `explode multiple aligned columns`() {
50+
val a by columnOf(listOf(1, 2), listOf(3, 4, 5))
51+
val b by columnOf(listOf(1, 2, 3), listOf(4, 5))
52+
53+
val df = dataFrameOf(a, b)
54+
val exploded = df.explode { a and b }
55+
56+
val expected = dataFrameOf("a", "b")(
57+
1, 1,
58+
2, 2,
59+
null, 3,
60+
3, 4,
61+
4, 5,
62+
5, null,
63+
)
64+
65+
exploded shouldBe expected
66+
}
67+
68+
@Test
69+
fun `explode with empty list and dropEmpty true`() {
70+
val df = dataFrameOf("a", "b")(
71+
1, listOf(1, 2),
72+
2, emptyList<Int>(),
73+
3, listOf(3),
74+
)
75+
76+
val exploded = df.explode(dropEmpty = true)
77+
78+
val expected = dataFrameOf("a", "b")(
79+
1, 1,
80+
1, 2,
81+
3, 3,
82+
)
83+
84+
exploded shouldBe expected
85+
}
86+
87+
@Test
88+
fun `explode with empty list and dropEmpty false`() {
89+
val df = dataFrameOf("a", "b")(
90+
1, listOf(1, 2),
91+
2, emptyList<Int>(),
92+
3, listOf(3),
93+
)
94+
95+
val exploded = df.explode(dropEmpty = false)
96+
97+
val expected = dataFrameOf("a", "b")(
98+
1, 1,
99+
1, 2,
100+
2, null,
101+
3, 3,
102+
)
103+
104+
exploded shouldBe expected
105+
}
106+
107+
@Test
108+
fun `explode DataColumn of lists`() {
109+
val col by columnOf(listOf(1, 2), listOf(3, 4))
110+
111+
val exploded = col.explode()
112+
val expected = columnOf(1, 2, 3, 4) named "col"
113+
114+
exploded shouldBe expected
115+
}
116+
117+
@Test
118+
fun `explode FrameColumn into ColumnGroup`() {
119+
val col by columnOf(
120+
dataFrameOf("x", "y")(1, 2, 3, 4),
121+
dataFrameOf("x", "y")(5, 6, 7, 8),
122+
)
123+
124+
val exploded = col.explode()
125+
126+
val expected = dataFrameOf("x", "y")(
127+
1, 2,
128+
3, 4,
129+
5, 6,
130+
7, 8,
131+
).asColumnGroup("col")
132+
133+
exploded shouldBe expected
134+
}
47135
}

0 commit comments

Comments
 (0)