@@ -3,9 +3,12 @@ package org.jetbrains.kotlinx.dataframe.api
3
3
import org.jetbrains.kotlinx.dataframe.DataColumn
4
4
import org.jetbrains.kotlinx.dataframe.DataFrame
5
5
import org.jetbrains.kotlinx.dataframe.DataRow
6
+ import org.jetbrains.kotlinx.dataframe.annotations.Interpretable
7
+ import org.jetbrains.kotlinx.dataframe.annotations.Refine
6
8
import org.jetbrains.kotlinx.dataframe.columns.values
7
9
import org.jetbrains.kotlinx.dataframe.impl.api.concatImpl
8
10
import org.jetbrains.kotlinx.dataframe.impl.asList
11
+ import org.jetbrains.kotlinx.dataframe.type
9
12
10
13
// region DataColumn
11
14
@@ -40,6 +43,64 @@ public fun <T> DataFrame<T>.concat(frames: Iterable<DataFrame<T>>): DataFrame<T>
40
43
41
44
public fun <T , G > GroupBy <T , G >.concat (): DataFrame <G > = groups.concat()
42
45
46
+ /* *
47
+ * Concatenates all groups in this [GroupBy] into a single [DataFrame],
48
+ * preserving and including all grouping key columns that are not present in the group's columns.
49
+ *
50
+ * Doesn't affect key columns that have the same name as columns inside the groups (even if their content differs).
51
+ *
52
+ * This function is especially useful when grouping by expressions or renamed columns,
53
+ * and you want the resulting [DataFrame] to include those keys as part of the output.
54
+ *
55
+ * ### Example
56
+ *
57
+ * ```kotlin
58
+ * val df = dataFrameOf(
59
+ * "value" to listOf(1, 2, 3, 3),
60
+ * "type" to listOf("a", "b", "a", "b")
61
+ * )
62
+ *
63
+ * val gb = df.groupBy { expr { "Category: ${type.uppercase()}" } named "category" }
64
+ * ```
65
+ *
66
+ * A regular `concat()` will return a [DataFrame] similar to the original `df`
67
+ * (with the same columns and rows but in the different orders):
68
+ *
69
+ * ```
70
+ * gb.concat()
71
+ * ```
72
+ * | value | type |
73
+ * | :---- | :--- |
74
+ * | 1 | a |
75
+ * | 3 | a |
76
+ * | 2 | b |
77
+ * | 3 | b |
78
+ *
79
+ * But `concatWithKeys()` will include the new "category" key column:
80
+ *
81
+ * ```
82
+ * gb.concatWithKeys()
83
+ * ```
84
+ * | value | type | category |
85
+ * | :---- | :--- | :------------ |
86
+ * | 1 | a | Category: A |
87
+ * | 3 | a | Category: A |
88
+ * | 2 | b | Category: B |
89
+ * | 3 | b | Category: B |
90
+ *
91
+ * @return A new [DataFrame] where all groups are combined and additional key columns are included in each row.
92
+ */
93
+ @Refine
94
+ @Interpretable(" ConcatWithKeys" )
95
+ public fun <T , G > GroupBy <T , G >.concatWithKeys (): DataFrame <G > =
96
+ mapToFrames {
97
+ val rowsCount = group.rowsCount()
98
+ val keyColumns = keys.columns().filter { it.name !in group.columnNames() }.map { keyColumn ->
99
+ DataColumn .createByType(keyColumn.name, List (rowsCount) { key[keyColumn] }, keyColumn.type)
100
+ }
101
+ group.addAll(keyColumns)
102
+ }.concat()
103
+
43
104
// endregion
44
105
45
106
// region ReducedGroupBy
0 commit comments