Improve groupingBy samples

This commit is contained in:
Ilya Gorbunov
2018-09-28 18:17:51 +03:00
parent 3a40e3f041
commit 12a31637d1
2 changed files with 48 additions and 67 deletions
@@ -6,8 +6,6 @@
package samples.collections package samples.collections
import samples.* import samples.*
import java.util.stream.Collector
import kotlin.test.*
class Grouping { class Grouping {
@@ -25,35 +23,34 @@ class Grouping {
@Sample @Sample
fun aggregateEvenAndOdd() { fun aggregateByRadix() {
val intList = listOf(0, 1, 2, 3, 4, 5, 6) val numbers = listOf(3, 4, 5, 6, 7, 8, 9)
// to multiply even number by 10 val aggregated = numbers.groupingBy { it % 3 }.aggregate { key, accumulator: StringBuilder?, element, first ->
val aggregated = intList.groupingBy { it % 2 == 0 }.aggregate { key, acc: Int?, element, _ -> if (first) // first element
when (key) { StringBuilder().append(key).append(":").append(element)
true -> element * 10 + (acc ?: 0) else
else -> element + (acc ?: 0) accumulator!!.append("-").append(element)
}
} }
assertPrints(aggregated, "{true=120, false=9}") assertPrints(aggregated.values, "[0:3-6-9, 1:4-7, 2:5-8]")
} }
@Sample @Sample
fun aggregateEvenAndOddTo() { fun aggregateByRadixTo() {
val intList = listOf(0, 1, 2, 3, 4, 5, 6) val numbers = listOf(3, 4, 5, 6, 7, 8, 9)
val aggregated = mutableMapOf<Boolean, Int>()
// to multiply even number by 10 val aggregated = numbers.groupingBy { it % 3 }.aggregateTo(mutableMapOf()) { key, accumulator: StringBuilder?, element, first ->
intList.groupingBy { it % 2 == 0 }.aggregateTo(aggregated, { key, acc: Int?, element, _ -> if (first) // first element
when (key) { StringBuilder().append(key).append(":").append(element)
true -> element * 10 + (acc ?: 0) else
else -> element + (acc ?: 0) accumulator!!.append("-").append(element)
} }
})
assertTrue(aggregated[true] == 120) assertPrints(aggregated.values, "[0:3-6-9, 1:4-7, 2:5-8]")
assertTrue(aggregated[false] == 9)
// aggregated is a mutable map
aggregated.clear()
} }
@Sample @Sample
@@ -63,8 +60,7 @@ class Grouping {
val evenFruits = fruits.groupingBy { it.first() } val evenFruits = fruits.groupingBy { it.first() }
.fold({ key, _ -> key to mutableListOf<String>() }, .fold({ key, _ -> key to mutableListOf<String>() },
{ _, accumulator, element -> { _, accumulator, element ->
if (element.length % 2 == 0) accumulator.second.add(element) accumulator.also { (_, list) -> if (element.length % 2 == 0) list.add(element) }
accumulator
}) })
val sorted = evenFruits.values.sortedBy { it.first } val sorted = evenFruits.values.sortedBy { it.first }
@@ -74,25 +70,18 @@ class Grouping {
@Sample @Sample
fun foldByEvenLengthWithComputedInitialValueTo() { fun foldByEvenLengthWithComputedInitialValueTo() {
val fruits = listOf("cherry", "blueberry", "citrus", "apple", "apricot", "banana", "coconut") val fruits = listOf("cherry", "blueberry", "citrus", "apple", "apricot", "banana", "coconut")
val evenFruits = mutableMapOf<Char, Pair<Char, MutableList<String>>>()
fruits.groupingBy { it.first() } val evenFruits = fruits.groupingBy { it.first() }
.foldTo(evenFruits, { key, _: String -> key to mutableListOf() }, .foldTo(mutableMapOf(), { key, _: String -> key to mutableListOf<String>() },
{ _, accumulator, element -> { _, accumulator, element ->
if (element.length % 2 == 0) accumulator.second.add(element) if (element.length % 2 == 0) accumulator.second.add(element)
accumulator accumulator
}) })
val sorted = evenFruits.values.sortedBy { it.first } val sorted = evenFruits.values.sortedBy { it.first }
assertPrints(sorted, "[(a, []), (b, [banana]), (c, [cherry, citrus])]")
assertTrue(sorted.first().first == 'a') evenFruits.clear() // evenFruits is a mutable map
assertTrue(sorted[0].second == emptyList<String>())
assertTrue(sorted[1].first == 'b')
assertTrue(sorted[1].second == listOf("banana"))
assertTrue(sorted.last().first == 'c')
assertTrue(sorted.last().second == listOf("cherry", "citrus"))
} }
@Sample @Sample
@@ -109,51 +98,43 @@ class Grouping {
@Sample @Sample
fun foldByEvenLengthWithConstantInitialValueTo() { fun foldByEvenLengthWithConstantInitialValueTo() {
val fruits = listOf("apple", "apricot", "banana", "blueberry", "cherry", "coconut") val fruits = listOf("apple", "apricot", "banana", "blueberry", "cherry", "coconut")
val evenFruits = mutableMapOf<Char, List<String>>()
// collect only even length Strings // collect only even length Strings
fruits.groupingBy { it.first() } val evenFruits = fruits.groupingBy { it.first() }
.foldTo(evenFruits, listOf()) { acc, e -> if (e.length % 2 == 0) acc + e else acc } .foldTo(mutableMapOf(), emptyList<String>()) { acc, e -> if (e.length % 2 == 0) acc + e else acc }
assertTrue(evenFruits['a'] == emptyList<String>()) assertPrints(evenFruits, "{a=[], b=[banana], c=[cherry]}")
assertTrue(evenFruits['b'] == listOf("banana"))
assertTrue(evenFruits['c'] == listOf("cherry")) evenFruits.clear() // evenFruits is a mutable map
} }
@Sample @Sample
fun reduceByMaxOfContainsVowels() { fun reduceByMaxVowels() {
val animals = listOf("raccoon", "reindeer", "cow", "camel", "giraffe", "goat") val animals = listOf("raccoon", "reindeer", "cow", "camel", "giraffe", "goat")
// grouping by first char and collect only max of contains vowels // grouping by first char and collect only max of contains vowels
val maxVowels = animals.groupingBy { it.first() } val compareByVowelCount = compareBy { s: String -> s.count { it in "aeiou" } }
.reduce { _, a, b ->
if (a.count { it in "aeiou" } >= b.count { it in "aeiou" }) { val maxVowels = animals.groupingBy { it.first() }.reduce { _, a, b -> maxOf(a, b, compareByVowelCount) }
a
} else {
b
}
}
assertPrints(maxVowels, "{r=reindeer, c=camel, g=giraffe}") assertPrints(maxVowels, "{r=reindeer, c=camel, g=giraffe}")
} }
@Sample @Sample
fun reduceByMaxOfContainsVowelsTo() { fun reduceByMaxVowelsTo() {
val animals = listOf("raccoon", "reindeer", "cow", "camel", "giraffe", "goat") val animals = listOf("raccoon", "reindeer", "cow", "camel", "giraffe", "goat")
val maxVowels = mutableMapOf<Char, String>() val maxVowels = mutableMapOf<Char, String>()
// grouping by first char and collect only max of contains vowels // grouping by first char and collect only max of contains vowels
animals.groupingBy { it.first() } val compareByVowelCount = compareBy { s: String -> s.count { it in "aeiou" } }
.reduceTo(maxVowels, { _, a, b ->
if (a.count { it in "aeiou" } >= b.count { it in "aeiou" }) {
a
} else {
b
}
})
assertTrue(maxVowels['r'] == "reindeer") animals.groupingBy { it.first() }.reduceTo(maxVowels) { _, a, b -> maxOf(a, b, compareByVowelCount) }
assertTrue(maxVowels['c'] == "camel")
assertTrue(maxVowels['g'] == "giraffe") assertPrints(maxVowels, "{r=reindeer, c=camel, g=giraffe}")
val moreAnimals = listOf("capybara", "rat")
moreAnimals.groupingBy { it.first() }.reduceTo(maxVowels) { _, a, b -> maxOf(a, b, compareByVowelCount) }
assertPrints(maxVowels, "{r=reindeer, c=capybara, g=giraffe}")
} }
} }
@@ -44,7 +44,7 @@ public interface Grouping<T, out K> {
* - `first`: indicates whether it's the 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. * @return a [Map] associating the key of each group with the result of aggregation of the group elements.
* @sample samples.collections.Grouping.aggregateEvenAndOdd * @sample samples.collections.Grouping.aggregateByRadix
*/ */
@SinceKotlin("1.1") @SinceKotlin("1.1")
public inline fun <T, K, R> Grouping<T, K>.aggregate( public inline fun <T, K, R> Grouping<T, K>.aggregate(
@@ -70,7 +70,7 @@ public inline fun <T, K, R> Grouping<T, K>.aggregate(
* then the elements being aggregated for that key are never considered as `first`. * 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. * @return the [destination] map associating the key of each group with the result of aggregation of the group elements.
* @sample samples.collections.Grouping.aggregateEvenAndOddTo * @sample samples.collections.Grouping.aggregateByRadixTo
*/ */
@SinceKotlin("1.1") @SinceKotlin("1.1")
public inline fun <T, K, R, M : MutableMap<in K, R>> Grouping<T, K>.aggregateTo( public inline fun <T, K, R, M : MutableMap<in K, R>> Grouping<T, K>.aggregateTo(
@@ -202,7 +202,7 @@ public inline fun <T, K, R, M : MutableMap<in K, R>> Grouping<T, K>.foldTo(
* - `element`: the element from the source being accumulated. * - `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. * @return a [Map] associating the key of each group with the result of accumulating the group elements.
* @sample samples.collections.Grouping.reduceByMaxOfContainsVowels * @sample samples.collections.Grouping.reduceByMaxVowels
*/ */
@SinceKotlin("1.1") @SinceKotlin("1.1")
public inline fun <S, T : S, K> Grouping<T, K>.reduce( public inline fun <S, T : S, K> Grouping<T, K>.reduce(
@@ -229,7 +229,7 @@ public inline fun <S, T : S, K> Grouping<T, K>.reduce(
* - `element`: the element from the source being folded; * - `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. * @return the [destination] map associating the key of each group with the result of accumulating the group elements.
* @sample samples.collections.Grouping.reduceByMaxOfContainsVowelsTo * @sample samples.collections.Grouping.reduceByMaxVowelsTo
*/ */
@SinceKotlin("1.1") @SinceKotlin("1.1")
public inline fun <S, T : S, K, M : MutableMap<in K, S>> Grouping<T, K>.reduceTo( public inline fun <S, T : S, K, M : MutableMap<in K, S>> Grouping<T, K>.reduceTo(