diff --git a/libraries/stdlib/src/kotlin/collections/Grouping.kt b/libraries/stdlib/src/kotlin/collections/Grouping.kt index 760843edf75..a5d01af4543 100644 --- a/libraries/stdlib/src/kotlin/collections/Grouping.kt +++ b/libraries/stdlib/src/kotlin/collections/Grouping.kt @@ -24,36 +24,38 @@ public interface Grouping { } /** - * Groups elements from the [Grouping] source by key and aggregates elements of each group with the specified [operation]. + * Groups elements from the [Grouping] source by key and applies [operation] to the elements of each group sequentially, + * passing the previously accumulated value and the current element as arguments, and stores the results in a new map. * * The key for each element is provided by the [Grouping.keyOf] function. * * @param operation function is invoked on each element with the following parameters: - * - `key`: the key of a group this element belongs to; - * - `value`: the current value of the accumulator of a group, can be `null` if it's first `element` encountered in the group; + * - `key`: the key of the group this element belongs to; + * - `accumulator`: the current value of the accumulator of the group, can be `null` if it's the first `element` encountered in the group; * - `element`: the element from the source being aggregated; - * - `first`: indicates whether it's first `element` encountered in the group. + * - `first`: indicates whether it's the first `element` encountered in the group. * * @return a [Map] associating the key of each group with the result of aggregation of the group elements. */ @SinceKotlin("1.1") public inline fun Grouping.aggregate( - operation: (key: K, value: R?, element: T, first: Boolean) -> R + operation: (key: K, accumulator: R?, element: T, first: Boolean) -> R ): Map { return aggregateTo(mutableMapOf(), operation) } /** - * Groups elements from the [Grouping] source by key and aggregates elements of each group with the specified [operation] - * to the given [destination] map. + * Groups elements from the [Grouping] source by key and applies [operation] to the elements of each group sequentially, + * passing the previously accumulated value and the current element as arguments, + * and stores the results in the given [destination] map. * * The key for each element is provided by the [Grouping.keyOf] function. * * @param operation a function that is invoked on each element with the following parameters: - * - `key`: the key of a group this element belongs to; - * - `accumulator`: the current value of the accumulator of the group, can be `null` if it's first `element` encountered in the group; + * - `key`: the key of the group this element belongs to; + * - `accumulator`: the current value of the accumulator of the group, can be `null` if it's the first `element` encountered in the group; * - `element`: the element from the source being aggregated; - * - `first`: indicates whether it's first `element` encountered in the group. + * - `first`: indicates whether it's the first `element` encountered in the group. * * If the [destination] map already has a value corresponding to some key, * then the elements being aggregated for that key are never considered as `first`. @@ -74,16 +76,17 @@ public inline fun > Grouping.aggregateTo( } /** - * Groups elements from the [Grouping] source by key and accumulates elements of each group with the specified [operation] - * starting with an initial value of accumulator provided by the [initialValueSelector] function. + * Groups elements from the [Grouping] source by key and applies [operation] to the elements of each group sequentially, + * passing the previously accumulated value and the current element as arguments, and stores the results in a new map. + * An initial value of accumulator is provided by [initialValueSelector] function. * - * @param initialValueSelector a function that provides an initial value of accumulator for an each group. + * @param initialValueSelector a function that provides an initial value of accumulator for each group. * It's invoked with parameters: - * - `key`: the key of a group; + * - `key`: the key of the group; * - `element`: the first element being encountered in that group. * * @param operation a function that is invoked on each element with the following parameters: - * - `key`: the key of a group this element belongs to; + * - `key`: the key of the group this element belongs to; * - `accumulator`: the current value of the accumulator of the group; * - `element`: the element from the source being accumulated. * @@ -94,23 +97,24 @@ public inline fun Grouping.fold( initialValueSelector: (key: K, element: T) -> R, operation: (key: K, accumulator: R, element: T) -> R ): Map = - aggregate { key, value, e, first -> operation(key, if (first) initialValueSelector(key, e) else value as R, e) } + aggregate { key, acc, e, first -> operation(key, if (first) initialValueSelector(key, e) else acc as R, e) } /** - * Groups elements from the [Grouping] source by key and accumulates elements of each group with the specified [operation] - * starting with an initial value of accumulator provided by the [initialValueSelector] function - * to the given [destination] map. + * Groups elements from the [Grouping] source by key and applies [operation] to the elements of each group sequentially, + * passing the previously accumulated value and the current element as arguments, + * and stores the results in the given [destination] map. + * An initial value of accumulator is provided by [initialValueSelector] function. * - * @param initialValueSelector a function that provides an initial value of accumulator for an each group. + * @param initialValueSelector a function that provides an initial value of accumulator for each group. * It's invoked with parameters: - * - `key`: the key of a group; + * - `key`: the key of the group; * - `element`: the first element being encountered in that group. * * If the [destination] map already has a value corresponding to some key, that value is used as an initial value of * the accumulator for that group and the [initialValueSelector] function is not called for that group. * * @param operation a function that is invoked on each element with the following parameters: - * - `key`: the key of a group this element belongs to; + * - `key`: the key of the group this element belongs to; * - `accumulator`: the current value of the accumulator of the group; * - `element`: the element from the source being accumulated. * @@ -122,12 +126,13 @@ public inline fun > Grouping.foldTo( initialValueSelector: (key: K, element: T) -> R, operation: (key: K, accumulator: R, element: T) -> R ): M = - aggregateTo(destination) { key, value, e, first -> operation(key, if (first) initialValueSelector(key, e) else value as R, e) } + aggregateTo(destination) { key, acc, e, first -> operation(key, if (first) initialValueSelector(key, e) else acc as R, e) } /** - * Groups elements from the [Grouping] source by key and accumulates elements of each group with the specified [operation] - * starting with the [initialValue]. + * Groups elements from the [Grouping] source by key and applies [operation] to the elements of each group sequentially, + * passing the previously accumulated value and the current element as arguments, and stores the results in a new map. + * An initial value of accumulator is the same [initialValue] for each group. * * @param operation a function that is invoked on each element with the following parameters: * - `accumulator`: the current value of the accumulator of the group; @@ -140,11 +145,13 @@ public inline fun Grouping.fold( initialValue: R, operation: (accumulator: R, element: T) -> R ): Map = - aggregate { k, v, e, first -> operation(if (first) initialValue else v as R, e) } + aggregate { _, acc, e, first -> operation(if (first) initialValue else acc as R, e) } /** - * Groups elements from the [Grouping] source by key and accumulates elements of each group with the specified [operation] - * starting with the [initialValue] to the given [destination] map. + * Groups elements from the [Grouping] source by key and applies [operation] to the elements of each group sequentially, + * passing the previously accumulated value and the current element as arguments, + * and stores the results in the given [destination] map. + * An initial value of accumulator is the same [initialValue] for each group. * * If the [destination] map already has a value corresponding to the key of some group, * that value is used as an initial value of the accumulator for that group. @@ -161,15 +168,18 @@ public inline fun > Grouping.foldTo( initialValue: R, operation: (accumulator: R, element: T) -> R ): M = - aggregateTo(destination) { k, v, e, first -> operation(if (first) initialValue else v as R, e) } + aggregateTo(destination) { _, acc, e, first -> operation(if (first) initialValue else acc as R, e) } /** - * Groups elements from the [Grouping] source by key and accumulates elements of each group with the specified [operation] - * starting the first element in that group. + * Groups elements from the [Grouping] source by key and applies the reducing [operation] to the elements of each group + * sequentially starting from the second element of the group, + * passing the previously accumulated value and the current element as arguments, + * and stores the results in a new map. + * An initial value of accumulator is the first element of the group. * * @param operation a function that is invoked on each subsequent element of the group with the following parameters: - * - `key`: the key of a group this element belongs to; + * - `key`: the key of the group this element belongs to; * - `accumulator`: the current value of the accumulator of the group; * - `element`: the element from the source being accumulated. * @@ -179,13 +189,16 @@ public inline fun > Grouping.foldTo( public inline fun Grouping.reduce( operation: (key: K, accumulator: S, element: T) -> S ): Map = - aggregate { key, value, e, first -> - if (first) e else operation(key, value as S, e) + aggregate { key, acc, e, first -> + if (first) e else operation(key, acc as S, e) } /** - * Groups elements from the [Grouping] source by key and accumulates elements of each group with the specified [operation] - * starting the first element in that group to the given [destination] map. + * Groups elements from the [Grouping] source by key and applies the reducing [operation] to the elements of each group + * sequentially starting from the second element of the group, + * passing the previously accumulated value and the current element as arguments, + * and stores the results in the given [destination] map. + * An initial value of accumulator is the first element of the group. * * If the [destination] map already has a value corresponding to the key of some group, * that value is used as an initial value of the accumulator for that group and the first element of that group is also @@ -202,53 +215,60 @@ public inline fun > Grouping.reduceTo destination: M, operation: (key: K, accumulator: S, element: T) -> S ): M = - aggregateTo(destination) { key, value, e, first -> - if (first) e else operation(key, value as S, e) + aggregateTo(destination) { key, acc, e, first -> + if (first) e else operation(key, acc as S, e) } /** * Groups elements from the [Grouping] source by key and counts elements in each group. * - * @return a [Map] associating the key of each group with the count of element in the group. + * @return a [Map] associating the key of each group with the count of elements in the group. */ @SinceKotlin("1.1") @JvmVersion public fun Grouping.eachCount(): Map = // fold(0) { acc, e -> acc + 1 } optimized for boxing foldTo( destination = mutableMapOf(), - initialValueSelector = { k, e -> kotlin.jvm.internal.Ref.IntRef() }, - operation = { k, acc, e -> acc.apply { element += 1 } }) + initialValueSelector = { _, _ -> kotlin.jvm.internal.Ref.IntRef() }, + operation = { _, acc, _ -> acc.apply { element += 1 } }) .mapValuesInPlace { it.value.element } /** * Groups elements from the [Grouping] source by key and counts elements in each group to the given [destination] map. * - * @return the [destination] map associating the key of each group with the count of element in the group. + * If the [destination] map already has a value corresponding to the key of some group, + * that value is used as an initial value of the counter for that group. + * + * @return the [destination] map associating the key of each group with the count of elements in the group. */ @SinceKotlin("1.1") public fun > Grouping.eachCountTo(destination: M): M = - foldTo(destination, 0) { acc, e -> acc + 1 } + foldTo(destination, 0) { acc, _ -> acc + 1 } /** * Groups elements from the [Grouping] source by key and sums values provided by the [valueSelector] function for elements in each group. * - * @return a [Map] associating the key of each group with the count of element in the group. + * @return a [Map] associating the key of each group with the sum of elements in the group. */ @SinceKotlin("1.1") @JvmVersion public inline fun Grouping.eachSumOf(valueSelector: (T) -> Int): Map = // fold(0) { acc, e -> acc + valueSelector(e)} optimized for boxing foldTo( destination = mutableMapOf(), - initialValueSelector = { k, e -> kotlin.jvm.internal.Ref.IntRef() }, - operation = { k, acc, e -> acc.apply { element += valueSelector(e) } }) + initialValueSelector = { _, _ -> kotlin.jvm.internal.Ref.IntRef() }, + operation = { _, acc, e -> acc.apply { element += valueSelector(e) } }) .mapValuesInPlace { it.value.element } /** * Groups elements from the [Grouping] source by key and sums values provided by the [valueSelector] function for elements in each group * to the given [destination] map. * - * @return the [destination] map associating the key of each group with the count of element in the group. + * + * If the [destination] map already has a value corresponding to the key of some group, + * that value is used as an initial value of the sum for that group. + * + * @return the [destination] map associating the key of each group with the sum of elements in the group. */ @SinceKotlin("1.1") public inline fun > Grouping.eachSumOfTo(destination: M, valueSelector: (T) -> Int): M =