From 2a2b417025f6e2e245a83127cb44a7c65ae0136c Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Wed, 28 Dec 2016 17:49:35 +0300 Subject: [PATCH] KEEP-23 implement group and fold operations Docs for group-and-fold operations Fix implementation for countEach and sumEachBy countEach and sumEachBy implementations for JS Rename keySelector to keyOf Generate additional sources for groupingBy + headers Rename countEach and sumEachBy to eachCount and eachSumOf. --- .../src/core/generated/_ArraysJs.kt | 12 + .../src/core/generated/_CollectionsJs.kt | 12 + .../src/core/generated/_SequencesJs.kt | 12 + .../src/core/generated/_StringsJs.kt | 12 + js/js.libraries/src/core/grouping.kt | 34 +++ .../stdlib/common/src/generated/_Arrays.kt | 7 + .../common/src/generated/_Collections.kt | 7 + .../stdlib/common/src/generated/_Sequences.kt | 7 + .../stdlib/common/src/generated/_Strings.kt | 7 + .../stdlib/common/src/kotlin/CollectionsH.kt | 5 + libraries/stdlib/src/generated/_Arrays.kt | 12 + .../stdlib/src/generated/_Collections.kt | 12 + libraries/stdlib/src/generated/_Sequences.kt | 12 + libraries/stdlib/src/generated/_Strings.kt | 12 + .../stdlib/src/kotlin/collections/Grouping.kt | 278 ++++++++++++++++++ .../reference-public-api/kotlin-stdlib.txt | 24 ++ .../src/templates/Mapping.kt | 27 ++ 17 files changed, 492 insertions(+) create mode 100644 js/js.libraries/src/core/grouping.kt create mode 100644 libraries/stdlib/src/kotlin/collections/Grouping.kt diff --git a/js/js.libraries/src/core/generated/_ArraysJs.kt b/js/js.libraries/src/core/generated/_ArraysJs.kt index da8756c4b7d..89ee0229421 100644 --- a/js/js.libraries/src/core/generated/_ArraysJs.kt +++ b/js/js.libraries/src/core/generated/_ArraysJs.kt @@ -7630,6 +7630,18 @@ public inline fun >> CharArray.groupBy return destination } +/** + * Creates a [Grouping] source from an array to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each element. + */ +@SinceKotlin("1.1") +public inline fun Array.groupingBy(crossinline keySelector: (T) -> K): Grouping { + return object : Grouping { + override fun elementIterator(): Iterator = this@groupingBy.iterator() + override fun keyOf(element: T): K = keySelector(element) + } +} + /** * Returns a list containing the results of applying the given [transform] function * to each element in the original array. diff --git a/js/js.libraries/src/core/generated/_CollectionsJs.kt b/js/js.libraries/src/core/generated/_CollectionsJs.kt index a374a628647..00257ec17f8 100644 --- a/js/js.libraries/src/core/generated/_CollectionsJs.kt +++ b/js/js.libraries/src/core/generated/_CollectionsJs.kt @@ -1179,6 +1179,18 @@ public inline fun >> Iterable.gr return destination } +/** + * Creates a [Grouping] source from a collection to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each element. + */ +@SinceKotlin("1.1") +public inline fun Iterable.groupingBy(crossinline keySelector: (T) -> K): Grouping { + return object : Grouping { + override fun elementIterator(): Iterator = this@groupingBy.iterator() + override fun keyOf(element: T): K = keySelector(element) + } +} + /** * Returns a list containing the results of applying the given [transform] function * to each element in the original collection. diff --git a/js/js.libraries/src/core/generated/_SequencesJs.kt b/js/js.libraries/src/core/generated/_SequencesJs.kt index 2f84d64589a..71e6916f900 100644 --- a/js/js.libraries/src/core/generated/_SequencesJs.kt +++ b/js/js.libraries/src/core/generated/_SequencesJs.kt @@ -644,6 +644,18 @@ public inline fun >> Sequence.gr return destination } +/** + * Creates a [Grouping] source from a sequence to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each element. + */ +@SinceKotlin("1.1") +public inline fun Sequence.groupingBy(crossinline keySelector: (T) -> K): Grouping { + return object : Grouping { + override fun elementIterator(): Iterator = this@groupingBy.iterator() + override fun keyOf(element: T): K = keySelector(element) + } +} + /** * Returns a sequence containing the results of applying the given [transform] function * to each element in the original sequence. diff --git a/js/js.libraries/src/core/generated/_StringsJs.kt b/js/js.libraries/src/core/generated/_StringsJs.kt index 88497fa5d70..dcad5646b53 100644 --- a/js/js.libraries/src/core/generated/_StringsJs.kt +++ b/js/js.libraries/src/core/generated/_StringsJs.kt @@ -701,6 +701,18 @@ public inline fun >> CharSequence.grou return destination } +/** + * Creates a [Grouping] source from a char sequence to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each character. + */ +@SinceKotlin("1.1") +public inline fun CharSequence.groupingBy(crossinline keySelector: (Char) -> K): Grouping { + return object : Grouping { + override fun elementIterator(): Iterator = this@groupingBy.iterator() + override fun keyOf(element: Char): K = keySelector(element) + } +} + /** * Returns a list containing the results of applying the given [transform] function * to each character in the original char sequence. diff --git a/js/js.libraries/src/core/grouping.kt b/js/js.libraries/src/core/grouping.kt new file mode 100644 index 00000000000..4c878b857b9 --- /dev/null +++ b/js/js.libraries/src/core/grouping.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package kotlin.collections + +/** + * 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. + */ +@SinceKotlin("1.1") +public fun Grouping.eachCount(): Map = + fold(0) { acc, e -> 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. + */ +@SinceKotlin("1.1") +public inline fun Grouping.eachSumOf(valueSelector: (T) -> Int): Map = + fold(0) { acc, e -> acc + valueSelector(e) } \ No newline at end of file diff --git a/libraries/stdlib/common/src/generated/_Arrays.kt b/libraries/stdlib/common/src/generated/_Arrays.kt index 62d6d259024..b07d1f6a8e2 100644 --- a/libraries/stdlib/common/src/generated/_Arrays.kt +++ b/libraries/stdlib/common/src/generated/_Arrays.kt @@ -4445,6 +4445,13 @@ public header inline fun >> BooleanArr */ public header inline fun >> CharArray.groupByTo(destination: M, keySelector: (Char) -> K, valueTransform: (Char) -> V): M +/** + * Creates a [Grouping] source from an array to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each element. + */ +@SinceKotlin("1.1") +public header inline fun Array.groupingBy(crossinline keySelector: (T) -> K): Grouping + /** * Returns a list containing the results of applying the given [transform] function * to each element in the original array. diff --git a/libraries/stdlib/common/src/generated/_Collections.kt b/libraries/stdlib/common/src/generated/_Collections.kt index 3f2b557d262..eb1c95ed05c 100644 --- a/libraries/stdlib/common/src/generated/_Collections.kt +++ b/libraries/stdlib/common/src/generated/_Collections.kt @@ -587,6 +587,13 @@ public header inline fun >> Iterable>> Iterable.groupByTo(destination: M, keySelector: (T) -> K, valueTransform: (T) -> V): M +/** + * Creates a [Grouping] source from a collection to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each element. + */ +@SinceKotlin("1.1") +public header inline fun Iterable.groupingBy(crossinline keySelector: (T) -> K): Grouping + /** * Returns a list containing the results of applying the given [transform] function * to each element in the original collection. diff --git a/libraries/stdlib/common/src/generated/_Sequences.kt b/libraries/stdlib/common/src/generated/_Sequences.kt index db6a478f0ab..1ce38dbf106 100644 --- a/libraries/stdlib/common/src/generated/_Sequences.kt +++ b/libraries/stdlib/common/src/generated/_Sequences.kt @@ -359,6 +359,13 @@ public header inline fun >> Sequence>> Sequence.groupByTo(destination: M, keySelector: (T) -> K, valueTransform: (T) -> V): M +/** + * Creates a [Grouping] source from a sequence to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each element. + */ +@SinceKotlin("1.1") +public header inline fun Sequence.groupingBy(crossinline keySelector: (T) -> K): Grouping + /** * Returns a sequence containing the results of applying the given [transform] function * to each element in the original sequence. diff --git a/libraries/stdlib/common/src/generated/_Strings.kt b/libraries/stdlib/common/src/generated/_Strings.kt index 4d9d91b55a1..197e1916f4b 100644 --- a/libraries/stdlib/common/src/generated/_Strings.kt +++ b/libraries/stdlib/common/src/generated/_Strings.kt @@ -422,6 +422,13 @@ public header inline fun >> CharSequen */ public header inline fun >> CharSequence.groupByTo(destination: M, keySelector: (Char) -> K, valueTransform: (Char) -> V): M +/** + * Creates a [Grouping] source from a char sequence to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each character. + */ +@SinceKotlin("1.1") +public header inline fun CharSequence.groupingBy(crossinline keySelector: (Char) -> K): Grouping + /** * Returns a list containing the results of applying the given [transform] function * to each character in the original char sequence. diff --git a/libraries/stdlib/common/src/kotlin/CollectionsH.kt b/libraries/stdlib/common/src/kotlin/CollectionsH.kt index ec705b72c6f..15fe1843055 100644 --- a/libraries/stdlib/common/src/kotlin/CollectionsH.kt +++ b/libraries/stdlib/common/src/kotlin/CollectionsH.kt @@ -154,3 +154,8 @@ header fun MutableList.sortWith(comparator: Comparator): Unit // from Maps.kt header operator fun MutableMap.set(key: K, value: V): Unit + + +// from Grouping.kt +public header fun Grouping.eachCount(): Map +public header inline fun Grouping.eachSumOf(valueSelector: (T) -> Int): Map \ No newline at end of file diff --git a/libraries/stdlib/src/generated/_Arrays.kt b/libraries/stdlib/src/generated/_Arrays.kt index cf5b026aad7..9dc84c4cd93 100644 --- a/libraries/stdlib/src/generated/_Arrays.kt +++ b/libraries/stdlib/src/generated/_Arrays.kt @@ -7713,6 +7713,18 @@ public inline fun >> CharArray.groupBy return destination } +/** + * Creates a [Grouping] source from an array to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each element. + */ +@SinceKotlin("1.1") +public inline fun Array.groupingBy(crossinline keySelector: (T) -> K): Grouping { + return object : Grouping { + override fun elementIterator(): Iterator = this@groupingBy.iterator() + override fun keyOf(element: T): K = keySelector(element) + } +} + /** * Returns a list containing the results of applying the given [transform] function * to each element in the original array. diff --git a/libraries/stdlib/src/generated/_Collections.kt b/libraries/stdlib/src/generated/_Collections.kt index 3eed5f12eaa..96dc2864b4c 100644 --- a/libraries/stdlib/src/generated/_Collections.kt +++ b/libraries/stdlib/src/generated/_Collections.kt @@ -1190,6 +1190,18 @@ public inline fun >> Iterable.gr return destination } +/** + * Creates a [Grouping] source from a collection to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each element. + */ +@SinceKotlin("1.1") +public inline fun Iterable.groupingBy(crossinline keySelector: (T) -> K): Grouping { + return object : Grouping { + override fun elementIterator(): Iterator = this@groupingBy.iterator() + override fun keyOf(element: T): K = keySelector(element) + } +} + /** * Returns a list containing the results of applying the given [transform] function * to each element in the original collection. diff --git a/libraries/stdlib/src/generated/_Sequences.kt b/libraries/stdlib/src/generated/_Sequences.kt index 0439366c14d..c69da3a8f45 100644 --- a/libraries/stdlib/src/generated/_Sequences.kt +++ b/libraries/stdlib/src/generated/_Sequences.kt @@ -663,6 +663,18 @@ public inline fun >> Sequence.gr return destination } +/** + * Creates a [Grouping] source from a sequence to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each element. + */ +@SinceKotlin("1.1") +public inline fun Sequence.groupingBy(crossinline keySelector: (T) -> K): Grouping { + return object : Grouping { + override fun elementIterator(): Iterator = this@groupingBy.iterator() + override fun keyOf(element: T): K = keySelector(element) + } +} + /** * Returns a sequence containing the results of applying the given [transform] function * to each element in the original sequence. diff --git a/libraries/stdlib/src/generated/_Strings.kt b/libraries/stdlib/src/generated/_Strings.kt index b94f1c51b4d..5ef4ca842b2 100644 --- a/libraries/stdlib/src/generated/_Strings.kt +++ b/libraries/stdlib/src/generated/_Strings.kt @@ -710,6 +710,18 @@ public inline fun >> CharSequence.grou return destination } +/** + * Creates a [Grouping] source from a char sequence to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each character. + */ +@SinceKotlin("1.1") +public inline fun CharSequence.groupingBy(crossinline keySelector: (Char) -> K): Grouping { + return object : Grouping { + override fun elementIterator(): Iterator = this@groupingBy.iterator() + override fun keyOf(element: Char): K = keySelector(element) + } +} + /** * Returns a list containing the results of applying the given [transform] function * to each character in the original char sequence. diff --git a/libraries/stdlib/src/kotlin/collections/Grouping.kt b/libraries/stdlib/src/kotlin/collections/Grouping.kt new file mode 100644 index 00000000000..d72aa4333b5 --- /dev/null +++ b/libraries/stdlib/src/kotlin/collections/Grouping.kt @@ -0,0 +1,278 @@ +package kotlin.collections + +/** + * Represents a source of elements with a [keyOf] function, which can be applied to each element to get its key. + * + * A [Grouping] structure serves as an intermediate step in group-and-fold operations: + * they group elements by their keys and then fold each group with some aggregating operation. + * + * It is created by attaching `keySelector: (T) -> K` function to a source of elements. + * To get an instance of [Grouping] use one of `groupingBy` extension functions: + * - [Iterable.groupingBy] + * - [Sequence.groupingBy] + * - [Array.groupingBy] + * - [CharSequence.groupingBy] + * + * For the list of group-and-fold operations available, see the [extension functions](#extension-functions) for `Grouping`. + */ +@SinceKotlin("1.1") +public interface Grouping { + /** Returns an [Iterator] which iterates through the elements of the source. */ + fun elementIterator(): Iterator + /** Extracts the key of an [element]. */ + fun keyOf(element: T): K +} + +/** + * Groups elements from the [Grouping] source by key and aggregates elements of each group with the specified [operation]. + * + * 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; + * - `element`: the element from the source being aggregated; + * - `first`: indicates whether it's 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 +): Map { + val result = mutableMapOf() + for (e in this.elementIterator()) { + val key = keyOf(e) + val value = result[key] + result[key] = operation(key, value, e, value == null && !result.containsKey(key)) + } + return result +} + +/** + * Groups elements from the [Grouping] source by key and aggregates elements of each group with the specified [operation] + * to 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; + * - `element`: the element from the source being aggregated; + * - `first`: indicates whether it's 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`. + * + * @return the [destination] map associating the key of each group with the result of aggregation of the group elements. + */ +@SinceKotlin("1.1") +public inline fun > Grouping.aggregateTo( + destination: M, + operation: (key: K, accumulator: R?, element: T, first: Boolean) -> R +): M { + for (e in this.elementIterator()) { + val key = keyOf(e) + val acc = destination[key] + destination[key] = operation(key, acc, e, acc == null && !destination.containsKey(key)) + } + return destination +} + +/** + * 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. + * + * @param initialValueSelector a function that provides an initial value of accumulator for an each group. + * It's invoked with parameters: + * - `key`: the key of a 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; + * - `accumulator`: the current value of the accumulator of the group; + * - `element`: the element from the source being accumulated. + * + * @return a [Map] associating the key of each group with the result of accumulating the group elements. + */ +@SinceKotlin("1.1") +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) } + +/** + * 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. + * + * @param initialValueSelector a function that provides an initial value of accumulator for an each group. + * It's invoked with parameters: + * - `key`: the key of a 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; + * - `accumulator`: the current value of the accumulator of the group; + * - `element`: the element from the source being accumulated. + * + * @return the [destination] map associating the key of each group with the result of accumulating the group elements. + */ +@SinceKotlin("1.1") +public inline fun > Grouping.foldTo( + destination: M, + 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) } + + +/** + * Groups elements from the [Grouping] source by key and accumulates elements of each group with the specified [operation] + * starting with the [initialValue]. + * + * @param operation a function that is invoked on each element with the following parameters: + * - `accumulator`: the current value of the accumulator of the group; + * - `element`: the element from the source being accumulated. + * + * @return a [Map] associating the key of each group with the result of accumulating the group elements. + */ +@SinceKotlin("1.1") +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) } + +/** + * 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. + * + * 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. + * + * @param operation a function that is invoked on each element with the following parameters: + * - `accumulator`: the current value of the accumulator of the group; + * - `element`: the element from the source being accumulated. + * + * @return the [destination] map associating the key of each group with the result of accumulating the group elements. + */ +@SinceKotlin("1.1") +public inline fun > Grouping.foldTo( + destination: M, + initialValue: R, + operation: (accumulator: R, element: T) -> R +): M = + aggregateTo(destination) { k, v, e, first -> operation(if (first) initialValue else v 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. + * + * @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; + * - `accumulator`: the current value of the accumulator of the group; + * - `element`: the element from the source being accumulated. + * + * @return a [Map] associating the key of each group with the result of accumulating the group elements. + */ +@SinceKotlin("1.1") +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) + } + +/** + * 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. + * + * 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 + * subjected to the [operation]. + + * @param operation a function that is invoked on each subsequent element of the group with the following parameters: + * - `accumulator`: the current value of the accumulator of the group; + * - `element`: the element from the source being folded; + * + * @return the [destination] map associating the key of each group with the result of accumulating the group elements. + */ +@SinceKotlin("1.1") +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) + } + + +/** + * 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. + */ +@SinceKotlin("1.1") +@JvmVersion +public fun Grouping.eachCount(): Map = + // fold(0) { acc, e -> acc + 1 } optimized for boxing + fold( + initialValueSelector = { k, e -> kotlin.jvm.internal.Ref.IntRef() }, + operation = { k, acc, e -> acc.apply { element += 1 } }) + .mapValues { 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. + */ +@SinceKotlin("1.1") +public fun > Grouping.eachCountTo(destination: M): M = + foldTo(destination, 0) { acc, e -> 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. + */ +@SinceKotlin("1.1") +@JvmVersion +public inline fun Grouping.eachSumOf(valueSelector: (T) -> Int): Map = + // fold(0) { acc, e -> acc + valueSelector(e)} optimized for boxing + fold( + initialValueSelector = { k, e -> kotlin.jvm.internal.Ref.IntRef() }, + operation = { k, acc, e -> acc.apply { element += valueSelector(e) } }) + .mapValues { 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. + */ +@SinceKotlin("1.1") +public inline fun > Grouping.eachSumOfTo(destination: M, valueSelector: (T) -> Int): M = + foldTo(destination, 0) { acc, e -> acc + valueSelector(e)} + + +/* +// TODO: sum by long and by double overloads + +public inline fun > Grouping.sumEachByLongTo(destination: M, valueSelector: (T) -> Long): M = + foldTo(destination, 0L) { acc, e -> acc + valueSelector(e)} + +public inline fun Grouping.sumEachByLong(valueSelector: (T) -> Long): Map = + fold(0L) { acc, e -> acc + valueSelector(e)} + +public inline fun > Grouping.sumEachByDoubleTo(destination: M, valueSelector: (T) -> Double): M = + foldTo(destination, 0.0) { acc, e -> acc + valueSelector(e)} + +public inline fun Grouping.sumEachByDouble(valueSelector: (T) -> Double): Map = + fold(0.0) { acc, e -> acc + valueSelector(e)} +*/ diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt index a9aa4cbf6d1..4ac8af9d52d 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt @@ -663,6 +663,7 @@ public final class kotlin/collections/ArraysKt { public static final fun groupByTo ([SLjava/util/Map;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun groupByTo ([ZLjava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun groupByTo ([ZLjava/util/Map;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; + public static final fun groupingBy ([Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlin/collections/Grouping; public static final fun indexOf ([BB)I public static final fun indexOf ([CC)I public static final fun indexOf ([DD)I @@ -1470,6 +1471,7 @@ public final class kotlin/collections/CollectionsKt { public static final fun groupBy (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun groupByTo (Ljava/lang/Iterable;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun groupByTo (Ljava/lang/Iterable;Ljava/util/Map;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; + public static final fun groupingBy (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Lkotlin/collections/Grouping; public static final fun indexOf (Ljava/lang/Iterable;Ljava/lang/Object;)I public static final fun indexOf (Ljava/util/List;Ljava/lang/Object;)I public static final fun indexOfFirst (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)I @@ -1607,6 +1609,26 @@ public final class kotlin/collections/CollectionsKt { public static final fun zip (Ljava/lang/Iterable;[Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/List; } +public abstract interface class kotlin/collections/Grouping { + public abstract fun elementIterator ()Ljava/util/Iterator; + public abstract fun keyOf (Ljava/lang/Object;)Ljava/lang/Object; +} + +public final class kotlin/collections/GroupingKt { + public static final fun aggregate (Lkotlin/collections/Grouping;Lkotlin/jvm/functions/Function4;)Ljava/util/Map; + public static final fun aggregateTo (Lkotlin/collections/Grouping;Ljava/util/Map;Lkotlin/jvm/functions/Function4;)Ljava/util/Map; + public static final fun eachCount (Lkotlin/collections/Grouping;)Ljava/util/Map; + public static final fun eachCountTo (Lkotlin/collections/Grouping;Ljava/util/Map;)Ljava/util/Map; + public static final fun eachSumOf (Lkotlin/collections/Grouping;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; + public static final fun eachSumOfTo (Lkotlin/collections/Grouping;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; + public static final fun fold (Lkotlin/collections/Grouping;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/Map; + public static final fun fold (Lkotlin/collections/Grouping;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;)Ljava/util/Map; + public static final fun foldTo (Lkotlin/collections/Grouping;Ljava/util/Map;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/Map; + public static final fun foldTo (Lkotlin/collections/Grouping;Ljava/util/Map;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;)Ljava/util/Map; + public static final fun reduce (Lkotlin/collections/Grouping;Lkotlin/jvm/functions/Function3;)Ljava/util/Map; + public static final fun reduceTo (Lkotlin/collections/Grouping;Ljava/util/Map;Lkotlin/jvm/functions/Function3;)Ljava/util/Map; +} + public final class kotlin/collections/IndexedValue { public fun (ILjava/lang/Object;)V public final fun component1 ()I @@ -2085,6 +2107,7 @@ public final class kotlin/sequences/SequencesKt { public static final fun groupBy (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun groupByTo (Lkotlin/sequences/Sequence;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun groupByTo (Lkotlin/sequences/Sequence;Ljava/util/Map;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; + public static final fun groupingBy (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/collections/Grouping; public static final fun indexOf (Lkotlin/sequences/Sequence;Ljava/lang/Object;)I public static final fun indexOfFirst (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)I public static final fun indexOfLast (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)I @@ -2428,6 +2451,7 @@ public final class kotlin/text/StringsKt { public static final fun groupBy (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun groupByTo (Ljava/lang/CharSequence;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun groupByTo (Ljava/lang/CharSequence;Ljava/util/Map;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; + public static final fun groupingBy (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function1;)Lkotlin/collections/Grouping; public static final fun hasSurrogatePairAt (Ljava/lang/CharSequence;I)Z public static final fun indexOf (Ljava/lang/CharSequence;CIZ)I public static final fun indexOf (Ljava/lang/CharSequence;Ljava/lang/String;IZ)I diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt index 3c1ecaf3c94..c8041b24f17 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt @@ -388,5 +388,32 @@ fun mapping(): List { } } + templates add f("groupingBy(crossinline keySelector: (T) -> K)") { + since("1.1") + inline(true) + only(Iterables, Sequences, ArraysOfObjects, CharSequences) + + typeParam("T") + typeParam("K") + + returns("Grouping") + + doc { f -> + """ + Creates a [Grouping] source from ${f.collection.prefixWithArticle()} to be used later with one of group-and-fold operations + using the specified [keySelector] function to extract a key from each ${f.element}. + """ + } + + body { + """ + return object : Grouping { + override fun elementIterator(): Iterator = this@groupingBy.iterator() + override fun keyOf(element: T): K = keySelector(element) + } + """ + } + } + return templates } \ No newline at end of file