@@ -15,9 +15,12 @@ import org.jetbrains.kotlinx.dataframe.columns.SingleColumn
1515import org.jetbrains.kotlinx.dataframe.columns.asColumnSet
1616import org.jetbrains.kotlinx.dataframe.columns.size
1717import org.jetbrains.kotlinx.dataframe.columns.values
18+ import org.jetbrains.kotlinx.dataframe.documentation.DocumentationUrls
1819import org.jetbrains.kotlinx.dataframe.documentation.DslGrammarTemplateColumnsSelectionDsl.DslGrammarTemplate
1920import org.jetbrains.kotlinx.dataframe.documentation.Indent
2021import org.jetbrains.kotlinx.dataframe.documentation.LineBreak
22+ import org.jetbrains.kotlinx.dataframe.documentation.RowFilterDescription
23+ import org.jetbrains.kotlinx.dataframe.documentation.SelectingColumns
2124import org.jetbrains.kotlinx.dataframe.impl.columns.TransformableColumnSet
2225import org.jetbrains.kotlinx.dataframe.impl.columns.singleOrNullWithTransformerImpl
2326import org.jetbrains.kotlinx.dataframe.impl.columns.transform
@@ -27,28 +30,167 @@ import kotlin.reflect.KProperty
2730
2831// region DataColumn
2932
33+ /* *
34+ * Returns the last value in this [DataColumn].
35+ *
36+ * See also [lastOrNull], [first], [take], [takeLast].
37+ *
38+ * @return The last value in this [DataColumn].
39+ *
40+ * @throws [IndexOutOfBoundsException] if the [DataColumn] is empty.
41+ */
3042public fun <T > DataColumn<T>.last (): T = get(size - 1 )
3143
44+ /* *
45+ * Returns the last value in this [DataColumn]. If the [DataColumn] is empty, returns `null`.
46+ *
47+ * See also [last], [first], [take], [takeLast].
48+ *
49+ * @return The last value in this [DataColumn], or `null` if the [DataColumn] is empty.
50+ */
3251public fun <T > DataColumn<T>.lastOrNull (): T ? = if (size > 0 ) last() else null
3352
53+ /* *
54+ * Returns the last value in this [DataColumn] that matches the given [predicate].
55+ *
56+ * ### Example
57+ * ```kotlin
58+ * // In a DataFrame of financial transactions sorted by time,
59+ * // find the amount of the most recent financial transaction over 100 euros
60+ * df.amount.last { it > 100 }
61+ * ```
62+ *
63+ * See also [lastOrNull], [first], [take], [takeLast].
64+ *
65+ * @param [predicate] A lambda expression used to get the last value
66+ * that satisfies a condition specified in this expression.
67+ * This predicate takes a value from the [DataColumn] as an input
68+ * and returns `true` if the value satisfies the condition or `false` otherwise.
69+ *
70+ * @return The last value in this [DataColumn] that matches the given [predicate].
71+ *
72+ * @throws [NoSuchElementException] if the [DataColumn] contains no element matching the [predicate]
73+ * (including the case when the [DataColumn] is empty).
74+ */
3475public inline fun <T > DataColumn<T>.last (predicate : (T ) -> Boolean ): T = values.last(predicate)
3576
77+ /* *
78+ * Returns the last value in this [DataColumn] that matches the given [predicate].
79+ * Returns `null` if the [DataColumn] contains no elements matching the [predicate]
80+ * (including the case when the [DataColumn] is empty).
81+ *
82+ * ### Example
83+ * ```kotlin
84+ * // In a DataFrame of financial transactions sorted by time,
85+ * // find the amount of the most recent financial transaction over 100 euros,
86+ * // or 'null' if there is no such transaction
87+ * df.amount.lastOrNull { it > 100 }
88+ * ```
89+ *
90+ * See also [last], [first], [take], [takeLast].
91+ *
92+ * @param [predicate] A lambda expression used to get the last value
93+ * that satisfies a condition specified in this expression.
94+ * This predicate takes a value from the [DataColumn] as an input
95+ * and returns `true` if the value satisfies the condition or `false` otherwise.
96+ *
97+ * @return The last value in this [DataColumn] that matches the given [predicate],
98+ * or `null` if the [DataColumn] contains no elements matching the [predicate].
99+ */
36100public inline fun <T > DataColumn<T>.lastOrNull (predicate : (T ) -> Boolean ): T ? = values.lastOrNull(predicate)
37101
38102// endregion
39103
40104// region DataFrame
41105
106+ /* *
107+ * Returns the last [row][DataRow] in this [DataFrame] that satisfies the given [predicate].
108+ * Returns `null` if the [DataFrame] contains no rows matching the [predicate]
109+ * (including the case when the [DataFrame] is empty).
110+ *
111+ * @include [RowFilterDescription]
112+ *
113+ * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention]
114+ *
115+ * ### Example
116+ * ```kotlin
117+ * // In a DataFrame of financial transactions sorted by time,
118+ * // obtain the most recent financial transaction with amount over 100 euros,
119+ * // or 'null' if there is no such transaction
120+ * df.lastOrNull { amount > 100 }
121+ * ```
122+ *
123+ * See also [last][DataFrame.last],
124+ * [first][DataFrame.first],
125+ * [take][DataFrame.take],
126+ * [takeLast][DataFrame.takeLast],
127+ * [takeWhile][DataFrame.takeWhile].
128+ *
129+ * @param [predicate] A [row filter][RowFilter] used to get the last value
130+ * that satisfies a condition specified in this filter.
131+ *
132+ * @return A [DataRow] containing the last row that matches the given [predicate],
133+ * or `null` if the [DataFrame] contains no rows matching the [predicate].
134+ */
42135public inline fun <T > DataFrame<T>.lastOrNull (predicate : RowFilter <T >): DataRow <T >? =
43136 rowsReversed().firstOrNull { predicate(it, it) }
44137
138+ /* *
139+ * Returns the last [row][DataRow] in this [DataFrame] that satisfies the given [predicate].
140+ *
141+ * @include [RowFilterDescription]
142+ *
143+ * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention]
144+ *
145+ * ### Example
146+ * ```kotlin
147+ * // In a DataFrame of financial transactions sorted by time,
148+ * // find the most recent financial transaction with amount over 100 euros
149+ * df.last { amount > 100 }
150+ * ```
151+ *
152+ * See also [lastOrNull][DataFrame.lastOrNull],
153+ * [first][DataFrame.first],
154+ * [take][DataFrame.take],
155+ * [takeLast][DataFrame.takeLast],
156+ * [takeWhile][DataFrame.takeWhile].
157+ *
158+ * @param [predicate] A [row filter][RowFilter] used to get the last value
159+ * that satisfies a condition specified in this filter.
160+ *
161+ * @return A [DataRow] containing the last row that matches the given [predicate].
162+ *
163+ * @throws [NoSuchElementException] if the [DataFrame] contains no rows matching the [predicate].
164+ */
45165public inline fun <T > DataFrame<T>.last (predicate : RowFilter <T >): DataRow <T > =
46166 rowsReversed().first {
47167 predicate(it, it)
48168 }
49169
170+ /* *
171+ * Returns the last [row][DataRow] in this [DataFrame]. If the [DataFrame] does not contain any rows, returns `null`.
172+ *
173+ * See also [last][DataFrame.last],
174+ * [first][DataFrame.first],
175+ * [take][DataFrame.take],
176+ * [takeLast][DataFrame.takeLast].
177+ *
178+ * @return A [DataRow] containing the last row in this [DataFrame], or `null` if the [DataFrame] is empty.
179+ */
50180public fun <T > DataFrame<T>.lastOrNull (): DataRow <T >? = if (nrow > 0 ) get(nrow - 1 ) else null
51181
182+ /* *
183+ * Returns the last [row][DataRow] in this [DataFrame].
184+ *
185+ * See also [lastOrNull][DataFrame.lastOrNull],
186+ * [first][DataFrame.first],
187+ * [take][DataFrame.take],
188+ * [takeLast][DataFrame.takeLast].
189+ *
190+ * @return A [DataRow] containing the last row in this [DataFrame].
191+ *
192+ * @throws NoSuchElementException if the [DataFrame] contains no rows.
193+ */
52194public fun <T > DataFrame<T>.last (): DataRow <T > {
53195 if (nrow == 0 ) {
54196 throw NoSuchElementException (" DataFrame has no rows. Use `lastOrNull`." )
@@ -60,26 +202,187 @@ public fun <T> DataFrame<T>.last(): DataRow<T> {
60202
61203// region GroupBy
62204
205+ /* *
206+ * [Reduces][GroupByDocs.Reducing] the groups of this [GroupBy]
207+ * by taking the last [row][DataRow] from each group,
208+ * and returns a [ReducedGroupBy] containing these rows
209+ * (one [row][DataRow] per group, each [row][DataRow] is the last [row][DataRow] in its group).
210+ *
211+ * If a group in this [GroupBy] is empty,
212+ * the corresponding [row][DataRow] in the resulting [ReducedGroupBy] will contain `null` values
213+ * for all columns in the group, except the grouping key.
214+ *
215+ * ### Example
216+ * ```kotlin
217+ * // In a DataFrame of order status logs sorted by time,
218+ * // find the most recent status for each order
219+ * df.groupBy { orderId }.last().concat()
220+ * ```
221+ *
222+ * See also [first][GroupBy.first].
223+ *
224+ * @return A [ReducedGroupBy] containing the last [row][DataRow]
225+ * (or a [row][DataRow] with `null` values, except the grouping key) from each group.
226+ */
63227@Interpretable(" GroupByReducePredicate" )
64228public fun <T , G > GroupBy <T , G >.last (): ReducedGroupBy <T , G > = reduce { lastOrNull() }
65229
230+ /* *
231+ * [Reduces][GroupByDocs.Reducing] the groups of this [GroupBy]
232+ * by taking from each group the last [row][DataRow] satisfying the given [predicate],
233+ * and returns a [ReducedGroupBy] containing these rows (one [row][DataRow] per group,
234+ * each [row][DataRow] is the last [row][DataRow] in its group that satisfies the [predicate]).
235+ *
236+ * If the group in [GroupBy] contains no matching rows,
237+ * the corresponding row in [ReducedGroupBy] will contain `null` values for all columns in the group,
238+ * except the grouping key.
239+ *
240+ * @include [RowFilterDescription]
241+ *
242+ * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention]
243+ *
244+ * ### Example
245+ * ```kotlin
246+ * // In a DataFrame of order status logs sorted by time,
247+ * // find the most recent status shown to the customer for each order
248+ * df.groupBy { orderId }.last { !isInternal }.concat()
249+ * ```
250+ *
251+ * See also [first][GroupBy.first].
252+ *
253+ * @param [predicate] A [row filter][RowFilter] used to get the last value
254+ * that satisfies a condition specified in this filter.
255+ *
256+ * @return A [ReducedGroupBy] containing the last [row][DataRow] matching the [predicate]
257+ * (or a [row][DataRow] with `null` values, except the grouping key) from each group.
258+ */
66259@Interpretable(" GroupByReducePredicate" )
67260public fun <T , G > GroupBy <T , G >.last (predicate : RowFilter <G >): ReducedGroupBy <T , G > = reduce { lastOrNull(predicate) }
68261
69262// endregion
70263
71264// region Pivot
72265
266+ /* *
267+ * [Reduces][PivotDocs.Reducing] this [Pivot] by taking the last [row][DataRow] from each group,
268+ * and returns a [ReducedPivot] that contains the last [row][DataRow] from the corresponding group in each column.
269+ *
270+ * For more information about [Pivot] with examples: {@include [DocumentationUrls.Pivot]}
271+ *
272+ * ### Example
273+ * ```kotlin
274+ * // In a DataFrame of real estate listings, find the most recent (if sorted by date and time)
275+ * // or the most expensive (if sorted by price) listing for each type of property (house, apartment, etc.)
276+ * df.pivot { type }.last().values()
277+ * ```
278+ *
279+ * See also [pivot], [reduce][Pivot.reduce], [first][Pivot.first].
280+ *
281+ * @return A [ReducedPivot] containing in each column the last [row][DataRow] from the corresponding group.
282+ */
73283public fun <T > Pivot<T>.last (): ReducedPivot <T > = reduce { lastOrNull() }
74284
285+ /* *
286+ * [Reduces][PivotDocs.Reducing] this [Pivot] by taking from each group the last [row][DataRow]
287+ * satisfying the given [predicate], and returns a [ReducedPivot] that contains the last [row][DataRow],
288+ * matching the [predicate], from the corresponding group in each column.
289+ *
290+ * For more information about [Pivot] with examples: {@include [DocumentationUrls.Pivot]}
291+ *
292+ * @include [RowFilterDescription]
293+ *
294+ * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention]
295+ *
296+ * ### Example
297+ * ```kotlin
298+ * // In a DataFrame of real estate listings sorted by date and time,
299+ * // find the most recent listing for each type of property (house, apartment, etc.)
300+ * // with the price less than 500,000 euros
301+ * df.pivot { type }.last { price < 500_000 }.values()
302+ * ```
303+ *
304+ * See also [pivot], [reduce][Pivot.reduce], [first][Pivot.first].
305+ *
306+ * @param [predicate] A [row filter][RowFilter] used to get the last value
307+ * that satisfies a condition specified in this filter.
308+ *
309+ * @return A [ReducedPivot] containing in each column the last [row][DataRow]
310+ * that satisfies the [predicate], from the corresponding group (or a [row][DataRow] with `null` values)
311+ */
75312public fun <T > Pivot<T>.last (predicate : RowFilter <T >): ReducedPivot <T > = reduce { lastOrNull(predicate) }
76313
77314// endregion
78315
79316// region PivotGroupBy
80317
318+ /* *
319+ * [Reduces][PivotGroupByDocs.Reducing] this [PivotGroupBy] by taking the last [row][DataRow]
320+ * from each combined [pivot] + [groupBy] group, and returns a [ReducedPivotGroupBy]
321+ * that contains the last row from each corresponding group.
322+ * If any combined [pivot] + [groupBy] group in [PivotGroupBy] is empty, in the resulting [ReducedPivotGroupBy]
323+ * it will be represented by a [row][DataRow] with `null` values (except the grouping key).
324+ *
325+ * For more information about [PivotGroupBy] with examples: {@include [DocumentationUrls.PivotGroupBy]}
326+ *
327+ * ### Example
328+ * ```kotlin
329+ * // In a DataFrame of real estate listings sorted by date and time,
330+ * // find the most recent listing for each combination of type of property (house, apartment, etc.)
331+ * // and the city it is located in
332+ * df.pivot { type }.groupBy { city }.last().values()
333+ * ```
334+ *
335+ * See also [groupBy][Pivot.groupBy],
336+ * [pivot][GroupBy.pivot],
337+ * [reduce][PivotGroupBy.reduce],
338+ * [first][PivotGroupBy.first].
339+ *
340+ * @return A [ReducedPivotGroupBy] containing in each combination of a [groupBy] key and a [pivot] key either
341+ * the last [row][DataRow] of the corresponding [DataFrame] formed by this pivot–group pair,
342+ * or a [row][DataRow] with `null` values (except the grouping key) if this [DataFrame] is empty.
343+ */
81344public fun <T > PivotGroupBy<T>.last (): ReducedPivotGroupBy <T > = reduce { lastOrNull() }
82345
346+ /* *
347+ * [Reduces][PivotGroupByDocs.Reducing] this [PivotGroupBy]
348+ * by taking from each combined [pivot] + [groupBy] group the last [row][DataRow] satisfying the given [predicate].
349+ * Returns a [ReducedPivotGroupBy] that contains the last [row][DataRow], matching the [predicate],
350+ * from each corresponding group.
351+ * If any combined [pivot] + [groupBy] group in [PivotGroupBy] does not contain any rows matching the [predicate],
352+ * in the resulting [ReducedPivotGroupBy] it will be represented by a [row][DataRow] with `null` values
353+ * (except the grouping key).
354+ *
355+ * @include [DocumentationUrls.PivotGroupBy]
356+ *
357+ * @include [DocumentationUrls.Pivot]
358+ *
359+ * @include [DocumentationUrls.GroupBy]
360+ *
361+ * @include [RowFilterDescription]
362+ *
363+ * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention]
364+ *
365+ * ### Example
366+ * ```kotlin
367+ * // In a DataFrame of real estate listings sorted by date and time,
368+ * // for each combination of type of property (house, apartment, etc.)
369+ * // and the city it is located in,
370+ * // find the most recent listing with the price less than 500,000 euros
371+ * df.pivot { type }.groupBy { city }.last { price < 500_000 }.values()
372+ * ```
373+ *
374+ * See also [groupBy][Pivot.groupBy],
375+ * [pivot][GroupBy.pivot],
376+ * [reduce][PivotGroupBy.reduce],
377+ * [first][PivotGroupBy.first].
378+ *
379+ * @param [predicate] A [row filter][RowFilter] used to get the last value
380+ * that satisfies a condition specified in this filter.
381+ *
382+ * @return A [ReducedPivotGroupBy] containing in each combination of a [groupBy] key and a [pivot] key either
383+ * the last matching the [predicate] [row][DataRow] of the corresponding [DataFrame] formed by this pivot–group pair,
384+ * or a [row][DataRow] with `null` values if this [DataFrame] does not contain any rows matching the [predicate].
385+ */
83386public fun <T > PivotGroupBy<T>.last (predicate : RowFilter <T >): ReducedPivotGroupBy <T > = reduce { lastOrNull(predicate) }
84387
85388// endregion
0 commit comments