@@ -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,32 +30,173 @@ import kotlin.reflect.KProperty
2730
2831// region DataColumn
2932
33+ /* *
34+ * Returns the first value in this [DataColumn].
35+ *
36+ * See also [firstOrNull], [last], [take], [takeLast].
37+ *
38+ * @return The first value in this [DataColumn].
39+ *
40+ * @throws [IndexOutOfBoundsException] if the [DataColumn] is empty.
41+ */
3042public fun <T > DataColumn<T>.first (): T = get(0 )
3143
44+ /* *
45+ * Returns the first value in this [DataColumn]. If the [DataColumn] is empty, returns `null`.
46+ *
47+ * See also [first], [last], [take], [takeLast].
48+ *
49+ * @return The first value in this [DataColumn], or `null` if the [DataColumn] is empty.
50+ */
3251public fun <T > DataColumn<T>.firstOrNull (): T ? = if (size > 0 ) first() else null
3352
53+ /* *
54+ * Returns the first 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 first transaction over 100 euros
60+ * df.amount.first { it > 100 }
61+ * ```
62+ *
63+ * See also [firstOrNull], [last], [take], [takeLast].
64+ *
65+ * @param [predicate] A lambda expression used to get the first 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 first value in this [DataColumn] that matches the given [predicate].
71+ *
72+ * @throws [NoSuchElementException] if the [DataColumn] contains no elements matching the [predicate]
73+ * (including the case when the [DataColumn] is empty).
74+ */
3475public fun <T > DataColumn<T>.first (predicate : (T ) -> Boolean ): T = values.first(predicate)
3576
77+ /* *
78+ * Returns the first 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 first transaction over 100 euros,
86+ * // or 'null' if there is no such transaction
87+ * df.amount.firstOrNull { it > 100 }
88+ * ```
89+ *
90+ * See also [first], [last], [take], [takeLast].
91+ *
92+ * @param [predicate] A lambda expression used to get the first 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 first value in this [DataColumn] that matches the given [predicate],
98+ * or `null` if the [DataColumn] contains no elements matching the [predicate].
99+ */
36100public fun <T > DataColumn<T>.firstOrNull (predicate : (T ) -> Boolean ): T ? = values.firstOrNull(predicate)
37101
38102// endregion
39103
40104// region DataFrame
41105
106+ /* *
107+ * Returns the first [row][DataRow] in this [DataFrame].
108+ *
109+ * See also [firstOrNull][DataFrame.firstOrNull],
110+ * [last][DataFrame.last],
111+ * [take][DataFrame.take],
112+ * [takeWhile][DataFrame.takeWhile],
113+ * [takeLast][DataFrame.takeLast].
114+ *
115+ * @return A [DataRow] containing the first row in this [DataFrame].
116+ *
117+ * @throws NoSuchElementException if the [DataFrame] contains no rows.
118+ */
42119public fun <T > DataFrame<T>.first (): DataRow <T > {
43120 if (nrow == 0 ) {
44121 throw NoSuchElementException (" DataFrame has no rows. Use `firstOrNull`." )
45122 }
46123 return get(0 )
47124}
48125
126+ /* *
127+ * Returns the first [row][DataRow] in this [DataFrame]. If the [DataFrame] does not contain any rows, returns `null`.
128+ *
129+ * See also [first][DataFrame.first],
130+ * [last][DataFrame.last],
131+ * [take][DataFrame.take],
132+ * [takeWhile][DataFrame.takeWhile],
133+ * [takeLast][DataFrame.takeLast].
134+ *
135+ * @return A [DataRow] containing the first row in this [DataFrame], or `null` if the [DataFrame] is empty.
136+ */
49137public fun <T > DataFrame<T>.firstOrNull (): DataRow <T >? = if (nrow > 0 ) first() else null
50138
139+ /* *
140+ * Returns the first [row][DataRow] in this [DataFrame] that satisfies the given [predicate].
141+ *
142+ * @include [RowFilterDescription]
143+ *
144+ * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention]
145+ *
146+ * ### Example
147+ * ```kotlin
148+ * // In a DataFrame of financial transactions sorted by time,
149+ * // find the first transaction with amount over 100 euros
150+ * df.first { amount > 100 }
151+ * ```
152+ *
153+ * See also [firstOrNull][DataFrame.firstOrNull],
154+ * [last][DataFrame.last],
155+ * [take][DataFrame.take],
156+ * [takeWhile][DataFrame.takeWhile],
157+ * [takeLast][DataFrame.takeLast].
158+ *
159+ * @param [predicate] A [row filter][RowFilter] used to get the first value
160+ * that satisfies a condition specified in this filter.
161+ *
162+ * @return A [DataRow] containing the first row that matches the given [predicate].
163+ *
164+ * @throws [NoSuchElementException] if the [DataFrame] contains no rows matching the [predicate].
165+ */
51166public inline fun <T > DataFrame<T>.first (predicate : RowFilter <T >): DataRow <T > =
52167 rows().first {
53168 predicate(it, it)
54169 }
55170
171+ /* *
172+ * Returns the first [row][DataRow] in this [DataFrame] that satisfies the given [predicate].
173+ * Returns `null` if the [DataFrame] contains no rows matching the [predicate]
174+ * (including the case when the [DataFrame] is empty).
175+ *
176+ * @include [RowFilterDescription]
177+ *
178+ * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention]
179+ *
180+ * ### Example
181+ * ```kotlin
182+ * // In a DataFrame of financial transactions sorted by time,
183+ * // find the first transaction with amount over 100 euros,
184+ * // or 'null' if there is no such transaction
185+ * df.firstOrNull { amount > 100 }
186+ * ```
187+ *
188+ * See also [first][DataFrame.first],
189+ * [last][DataFrame.last],
190+ * [take][DataFrame.take],
191+ * [takeWhile][DataFrame.takeWhile],
192+ * [takeLast][DataFrame.takeLast].
193+ *
194+ * @param [predicate] A [row filter][RowFilter] used to get the first value
195+ * that satisfies a condition specified in this filter.
196+ *
197+ * @return A [DataRow] containing the first row that matches the given [predicate],
198+ * or `null` if the [DataFrame] contains no rows matching the [predicate].
199+ */
56200public inline fun <T > DataFrame<T>.firstOrNull (predicate : RowFilter <T >): DataRow <T >? =
57201 rows().firstOrNull {
58202 predicate(it, it)
@@ -62,26 +206,186 @@ public inline fun <T> DataFrame<T>.firstOrNull(predicate: RowFilter<T>): DataRow
62206
63207// region GroupBy
64208
209+ /* *
210+ * [Reduces][GroupByDocs.Reducing] the groups of this [GroupBy]
211+ * by taking the first [row][DataRow] from each group,
212+ * and returns a [ReducedGroupBy] containing these rows
213+ * (one [row][DataRow] per group, each [row][DataRow] is the first [row][DataRow] in its group).
214+ *
215+ * If a group in this [GroupBy] is empty,
216+ * the corresponding [row][DataRow] in the resulting [ReducedGroupBy] will contain `null` values
217+ * for all columns in the group, except the grouping key.
218+ *
219+ * ### Example
220+ * ```kotlin
221+ * // In a DataFrame of orders sorted by date and time,
222+ * // find the first order placed by each customer
223+ * df.groupBy { customerId }.first().concat()
224+ * ```
225+ *
226+ * See also [last][GroupBy.last].
227+ *
228+ * @return A [ReducedGroupBy] containing the first [row][DataRow]
229+ * (or a [row][DataRow] with `null` values, except the grouping key) from each group.
230+ */
65231@Interpretable(" GroupByReducePredicate" )
66232public fun <T , G > GroupBy <T , G >.first (): ReducedGroupBy <T , G > = reduce { firstOrNull() }
67233
234+ /* *
235+ * [Reduces][GroupByDocs.Reducing] the groups of this [GroupBy]
236+ * by taking from each group the first [row][DataRow] satisfying the given [predicate],
237+ * and returns a [ReducedGroupBy] containing these rows (one [row][DataRow] per group,
238+ * each [row][DataRow] is the first [row][DataRow] in its group that satisfies the [predicate]).
239+ *
240+ * If the group in [GroupBy] contains no matching rows,
241+ * the corresponding row in [ReducedGroupBy] will contain `null` values for all columns in the group,
242+ * except the grouping key.
243+ *
244+ * @include [RowFilterDescription]
245+ *
246+ * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention]
247+ *
248+ * ### Example
249+ * ```kotlin
250+ * // In a DataFrame of orders sorted by date and time,
251+ * // find the first order over 100 euros placed by each customer
252+ * df.groupBy { customerId }.first { total > 100 }.concat()
253+ * ```
254+ *
255+ * See also [last][GroupBy.last].
256+ *
257+ * @param [predicate] A [row filter][RowFilter] used to get the first value
258+ * that satisfies a condition specified in this filter.
259+ *
260+ * @return A [ReducedGroupBy] containing the first [row][DataRow] matching the [predicate]
261+ * (or a [row][DataRow] with `null` values, except the grouping key) from each group.
262+ */
68263@Interpretable(" GroupByReducePredicate" )
69264public fun <T , G > GroupBy <T , G >.first (predicate : RowFilter <G >): ReducedGroupBy <T , G > = reduce { firstOrNull(predicate) }
70265
71266// endregion
72267
73268// region Pivot
74269
270+ /* *
271+ * [Reduces][PivotDocs.Reducing] this [Pivot] by taking the first [row][DataRow] from each group,
272+ * and returns a [ReducedPivot] that contains the first [row][DataRow] from the corresponding group in each column.
273+ *
274+ * For more information about [Pivot] with examples: {@include [DocumentationUrls.Pivot]}
275+ *
276+ * ### Example
277+ * ```kotlin
278+ * // In a DataFrame of real estate listings sorted by price,
279+ * // find the cheapest listing for each type of property (house, apartment, etc.)
280+ * df.pivot { type }.first().values()
281+ * ```
282+ *
283+ * See also [pivot], [reduce][Pivot.reduce], [last][Pivot.last].
284+ *
285+ * @return A [ReducedPivot] containing in each column the first [row][DataRow] from the corresponding group.
286+ */
75287public fun <T > Pivot<T>.first (): ReducedPivot <T > = reduce { firstOrNull() }
76288
289+ /* *
290+ * [Reduces][PivotDocs.Reducing] this [Pivot] by taking from each group the first [row][DataRow]
291+ * satisfying the given [predicate], and returns a [ReducedPivot] that contains the first row, matching the [predicate],
292+ * from the corresponding group in each column.
293+ *
294+ * For more information about [Pivot] with examples: {@include [DocumentationUrls.Pivot]}
295+ *
296+ * @include [RowFilterDescription]
297+ *
298+ * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention]
299+ *
300+ * ### Example
301+ * ```kotlin
302+ * // In a DataFrame of real estate listings sorted by price,
303+ * // find the cheapest listing for each type of property (house, apartment, etc.)
304+ * // with is not yet sold out.
305+ * df.pivot { type }.first { !soldOut }.values()
306+ * ```
307+ *
308+ * See also [pivot], [reduce][Pivot.reduce], [last][Pivot.last].
309+ *
310+ * @param [predicate] A [row filter][RowFilter] used to get the first value
311+ * that satisfies a condition specified in this filter.
312+ *
313+ * @return A [ReducedPivot] containing in each column the first [row][DataRow]
314+ * that satisfies the [predicate], from the corresponding group (or a [row][DataRow] with `null` values).
315+ */
77316public fun <T > Pivot<T>.first (predicate : RowFilter <T >): ReducedPivot <T > = reduce { firstOrNull(predicate) }
78317
79318// endregion
80319
81320// region PivotGroupBy
82321
322+ /* *
323+ * [Reduces][PivotGroupByDocs.Reducing] this [PivotGroupBy] by taking the first [row][DataRow]
324+ * from each combined [pivot] + [groupBy] group, and returns a [ReducedPivotGroupBy]
325+ * that contains the first row from each corresponding group.
326+ * If any combined [pivot] + [groupBy] group in [PivotGroupBy] is empty, in the resulting [ReducedPivotGroupBy]
327+ * it will be represented by a [row][DataRow] with `null` values (except the grouping key).
328+ *
329+ * For more information about [PivotGroupBy] with examples: {@include [DocumentationUrls.PivotGroupBy]}
330+ *
331+ * ### Example
332+ * ```kotlin
333+ * // In a DataFrame of real estate listings sorted by price,
334+ * // find the cheapest listing for each combination of type of property (house, apartment, etc.)
335+ * // and the city it is located in
336+ * df.pivot { type }.groupBy { city }.first().values()
337+ * ```
338+ *
339+ * See also [groupBy][Pivot.groupBy],
340+ * [pivot][GroupBy.pivot],
341+ * [reduce][PivotGroupBy.reduce],
342+ * [last][PivotGroupBy.last].
343+ *
344+ * @return A [ReducedPivotGroupBy] containing in each combination of a [groupBy] key and a [pivot] key either
345+ * the first [row][DataRow] of the corresponding [DataFrame] formed by this pivot–group pair,
346+ * or a [row][DataRow] with `null` values (except the grouping key) if this [DataFrame] is empty.
347+ */
83348public fun <T > PivotGroupBy<T>.first (): ReducedPivotGroupBy <T > = reduce { firstOrNull() }
84349
350+ /* *
351+ * [Reduces][PivotGroupByDocs.Reducing] this [PivotGroupBy]
352+ * by taking from each combined [pivot] + [groupBy] group the first [row][DataRow] satisfying the given [predicate].
353+ * Returns a [ReducedPivotGroupBy] that contains the first row, matching the [predicate], from each corresponding group.
354+ * If any combined [pivot] + [groupBy] group in [PivotGroupBy] does not contain any rows matching the [predicate],
355+ * in the resulting [ReducedPivotGroupBy] it will be represented by a [row][DataRow] with `null` values
356+ * (except the grouping key).
357+ *
358+ * @include [DocumentationUrls.PivotGroupBy]
359+ *
360+ * @include [DocumentationUrls.Pivot]
361+ *
362+ * @include [DocumentationUrls.GroupBy]
363+ *
364+ * @include [RowFilterDescription]
365+ *
366+ * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention]
367+ *
368+ * ### Example
369+ * ```kotlin
370+ * // In a DataFrame of real estate listings sorted by price,
371+ * // for each combination of type of property (house, apartment, etc.)
372+ * // and the city it is located in,
373+ * // find the cheapest listing that is not yet sold out
374+ * df.pivot { type }.groupBy { city }.first { !soldOut }.values()
375+ * ```
376+ *
377+ * See also [groupBy][Pivot.groupBy],
378+ * [pivot][GroupBy.pivot],
379+ * [reduce][PivotGroupBy.reduce],
380+ * [last][PivotGroupBy.last].
381+ *
382+ * @param [predicate] A [row filter][RowFilter] used to get the first value
383+ * that satisfies a condition specified in this filter.
384+ *
385+ * @return A [ReducedPivotGroupBy] containing in each combination of a [groupBy] key and a [pivot] key either
386+ * the first matching the [predicate] [row][DataRow] of the corresponding [DataFrame] formed by this pivot–group pair,
387+ * or a [row][DataRow] with `null` values if this [DataFrame] does not contain any rows matching the [predicate].
388+ */
85389public fun <T > PivotGroupBy<T>.first (predicate : RowFilter <T >): ReducedPivotGroupBy <T > =
86390 reduce { firstOrNull(predicate) }
87391
0 commit comments