avoid default arguments on groupBy() by having groupByTo() if the caller wishes to specify the Map to group into. Also tidied up the sample code in CollectionTest

This commit is contained in:
James Strachan
2012-04-12 12:35:13 +01:00
parent 46dbd19433
commit c3f1e38c67
6 changed files with 49 additions and 41 deletions
@@ -141,11 +141,18 @@ public inline fun <T> Array<T>.fold(initial: T, operation: (T, T) -> T): T {
public inline fun <T> Array<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation) public inline fun <T> Array<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation)
/** /**
* Transforms each element using the result as the key in a map to group elements by the result * Groups the elements in the collection into a new [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
* *
* @includeFunctionBody ../../test/CollectionTest.kt groupBy * @includeFunctionBody ../../test/CollectionTest.kt groupBy
*/ */
public inline fun <T, K> Array<T>.groupBy(result: Map<K, List<T>> = HashMap<K, List<T>>(), toKey: (T) -> K) : Map<K, List<T>> { public inline fun <T, K> Array<T>.groupBy(toKey: (T) -> K) : Map<K, List<T>> = groupByTo<T,K>(HashMap<K, List<T>>(), toKey)
/**
* Groups the elements in the collection into the given [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
*
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
*/
public inline fun <T, K> Array<T>.groupByTo(result: Map<K, List<T>>, toKey: (T) -> K) : Map<K, List<T>> {
for (element in this) { for (element in this) {
val key = toKey(element) val key = toKey(element)
val list = result.getOrPut(key) { ArrayList<T>() } val list = result.getOrPut(key) { ArrayList<T>() }
@@ -160,7 +167,7 @@ public inline fun <T, K> Array<T>.groupBy(result: Map<K, List<T>> = HashMap<K, L
* If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will * If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will
* a special *truncated* separator (which defaults to "..." * a special *truncated* separator (which defaults to "..."
* *
* @includeFunctionBody ../../test/CollectionTest.kt appendString * @includeFunctionBody ../../test/CollectionTest.kt makeString
*/ */
public inline fun <T> Array<T>.makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String { public inline fun <T> Array<T>.makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String {
val buffer = StringBuilder() val buffer = StringBuilder()
@@ -139,11 +139,18 @@ public inline fun <T> java.util.Iterator<T>.fold(initial: T, operation: (T, T) -
public inline fun <T> java.util.Iterator<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation) public inline fun <T> java.util.Iterator<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation)
/** /**
* Transforms each element using the result as the key in a map to group elements by the result * Groups the elements in the collection into a new [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
* *
* @includeFunctionBody ../../test/CollectionTest.kt groupBy * @includeFunctionBody ../../test/CollectionTest.kt groupBy
*/ */
public inline fun <T, K> java.util.Iterator<T>.groupBy(result: Map<K, List<T>> = HashMap<K, List<T>>(), toKey: (T) -> K) : Map<K, List<T>> { public inline fun <T, K> java.util.Iterator<T>.groupBy(toKey: (T) -> K) : Map<K, List<T>> = groupByTo<T,K>(HashMap<K, List<T>>(), toKey)
/**
* Groups the elements in the collection into the given [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
*
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
*/
public inline fun <T, K> java.util.Iterator<T>.groupByTo(result: Map<K, List<T>>, toKey: (T) -> K) : Map<K, List<T>> {
for (element in this) { for (element in this) {
val key = toKey(element) val key = toKey(element)
val list = result.getOrPut(key) { ArrayList<T>() } val list = result.getOrPut(key) { ArrayList<T>() }
@@ -158,7 +165,7 @@ public inline fun <T, K> java.util.Iterator<T>.groupBy(result: Map<K, List<T>> =
* If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will * If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will
* a special *truncated* separator (which defaults to "..." * a special *truncated* separator (which defaults to "..."
* *
* @includeFunctionBody ../../test/CollectionTest.kt appendString * @includeFunctionBody ../../test/CollectionTest.kt makeString
*/ */
public inline fun <T> java.util.Iterator<T>.makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String { public inline fun <T> java.util.Iterator<T>.makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String {
val buffer = StringBuilder() val buffer = StringBuilder()
@@ -141,11 +141,18 @@ public inline fun <T> Iterable<T>.fold(initial: T, operation: (T, T) -> T): T {
public inline fun <T> Iterable<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation) public inline fun <T> Iterable<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation)
/** /**
* Transforms each element using the result as the key in a map to group elements by the result * Groups the elements in the collection into a new [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
* *
* @includeFunctionBody ../../test/CollectionTest.kt groupBy * @includeFunctionBody ../../test/CollectionTest.kt groupBy
*/ */
public inline fun <T, K> Iterable<T>.groupBy(result: Map<K, List<T>> = HashMap<K, List<T>>(), toKey: (T) -> K) : Map<K, List<T>> { public inline fun <T, K> Iterable<T>.groupBy(toKey: (T) -> K) : Map<K, List<T>> = groupByTo<T,K>(HashMap<K, List<T>>(), toKey)
/**
* Groups the elements in the collection into the given [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
*
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
*/
public inline fun <T, K> Iterable<T>.groupByTo(result: Map<K, List<T>>, toKey: (T) -> K) : Map<K, List<T>> {
for (element in this) { for (element in this) {
val key = toKey(element) val key = toKey(element)
val list = result.getOrPut(key) { ArrayList<T>() } val list = result.getOrPut(key) { ArrayList<T>() }
@@ -160,7 +167,7 @@ public inline fun <T, K> Iterable<T>.groupBy(result: Map<K, List<T>> = HashMap<K
* If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will * If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will
* a special *truncated* separator (which defaults to "..." * a special *truncated* separator (which defaults to "..."
* *
* @includeFunctionBody ../../test/CollectionTest.kt appendString * @includeFunctionBody ../../test/CollectionTest.kt makeString
*/ */
public inline fun <T> Iterable<T>.makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String { public inline fun <T> Iterable<T>.makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String {
val buffer = StringBuilder() val buffer = StringBuilder()
@@ -138,11 +138,18 @@ public inline fun <T> java.lang.Iterable<T>.fold(initial: T, operation: (T, T) -
public inline fun <T> java.lang.Iterable<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation) public inline fun <T> java.lang.Iterable<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation)
/** /**
* Transforms each element using the result as the key in a map to group elements by the result * Groups the elements in the collection into a new [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
* *
* @includeFunctionBody ../../test/CollectionTest.kt groupBy * @includeFunctionBody ../../test/CollectionTest.kt groupBy
*/ */
public inline fun <T, K> java.lang.Iterable<T>.groupBy(result: Map<K, List<T>> = HashMap<K, List<T>>(), toKey: (T) -> K) : Map<K, List<T>> { public inline fun <T, K> java.lang.Iterable<T>.groupBy(toKey: (T) -> K) : Map<K, List<T>> = groupByTo<T,K>(HashMap<K, List<T>>(), toKey)
/**
* Groups the elements in the collection into the given [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
*
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
*/
public inline fun <T, K> java.lang.Iterable<T>.groupByTo(result: Map<K, List<T>>, toKey: (T) -> K) : Map<K, List<T>> {
for (element in this) { for (element in this) {
val key = toKey(element) val key = toKey(element)
val list = result.getOrPut(key) { ArrayList<T>() } val list = result.getOrPut(key) { ArrayList<T>() }
+7 -27
View File
@@ -120,9 +120,9 @@ class CollectionTest {
} }
} }
// TODO would be nice to avoid the <String>
test fun filterIntoSet() { test fun filterIntoSet() {
val data = arrayList("foo", "bar") val data = arrayList("foo", "bar")
// TODO would be nice to avoid the <String>
val foo = data.filterTo(hashSet<String>()){it.startsWith("f")} val foo = data.filterTo(hashSet<String>()){it.startsWith("f")}
assertTrue { assertTrue {
@@ -136,9 +136,9 @@ class CollectionTest {
} }
} }
// TODO would be nice to avoid the <String>
test fun filterIntoSortedSet() { test fun filterIntoSortedSet() {
val data = arrayList("foo", "bar") val data = arrayList("foo", "bar")
// TODO would be nice to avoid the <String>
val sorted = data.filterTo(sortedSet<String>()){it.length == 3} val sorted = data.filterTo(sortedSet<String>()){it.length == 3}
assertEquals(2, sorted.size) assertEquals(2, sorted.size)
assertEquals(sortedSet("bar", "foo"), sorted) assertEquals(sortedSet("bar", "foo"), sorted)
@@ -176,59 +176,39 @@ class CollectionTest {
assertEquals(6, count) assertEquals(6, count)
} }
/*
// TODO would be nice to be able to write this as this
//numbers.fold(0){it + it2}
numbers.fold(0){(it, it2) -> it + it2}
// TODO would be nice to be able to write this as this
// numbers.map{it.toString()}.fold(""){it + it2}
numbers.map<Int, String>{it.toString()}.fold(""){(it, it2) -> it + it2}
*/
test fun fold() { test fun fold() {
// lets calculate the sum of some numbers // lets calculate the sum of some numbers
expect(10) { expect(10) {
val numbers = arrayList(1, 2, 3, 4) val numbers = arrayList(1, 2, 3, 4)
numbers.fold(0){(it, it2) -> it + it2} numbers.fold(0){ a, b -> a + b}
} }
expect(0) { expect(0) {
val numbers = arrayList<Int>() val numbers = arrayList<Int>()
numbers.fold(0){(it, it2) -> it + it2} numbers.fold(0){ a, b -> a + b}
} }
// lets concatenate some strings // lets concatenate some strings
expect("1234") { expect("1234") {
val numbers = arrayList(1, 2, 3, 4) val numbers = arrayList(1, 2, 3, 4)
numbers.map<Int, String>{it.toString()}.fold(""){(it, it2) -> it + it2} numbers.map<Int, String>{it.toString()}.fold(""){ a, b -> a + b}
} }
} }
/*
// TODO would be nice to be able to write this as this
// numbers.map{it.toString()}.foldRight(""){it + it2}
numbers.map<Int, String>{it.toString()}.foldRight(""){(it, it2) -> it + it2}
*/
test fun foldRight() { test fun foldRight() {
expect("4321") { expect("4321") {
val numbers = arrayList(1, 2, 3, 4) val numbers = arrayList(1, 2, 3, 4)
numbers.map<Int, String>{it.toString()}.foldRight(""){(it, it2) -> it + it2} numbers.map<Int, String>{it.toString()}.foldRight(""){ a, b -> a + b}
} }
} }
/*
TODO inference engine should not need this type info?
val byLength = words.groupBy<String, Int>{it.length}
*/
test fun groupBy() { test fun groupBy() {
val words = arrayList("a", "ab", "abc", "def", "abcd") val words = arrayList("a", "ab", "abc", "def", "abcd")
val byLength = words.groupBy<String, Int>{it.length} val byLength = words.groupBy{ it.length }
assertEquals(4, byLength.size()) assertEquals(4, byLength.size())
val l3 = byLength.getOrElse(3, {ArrayList<String>()}) val l3 = byLength.getOrElse(3, {ArrayList<String>()})
assertEquals(2, l3.size) assertEquals(2, l3.size)
} }
test fun makeString() { test fun makeString() {
@@ -136,14 +136,14 @@ fun inheritedExtensionProperties(properties: Collection<KProperty>): Map<KClass,
// TODO for some reason the SortedMap causes kotlin to freak out a little :) // TODO for some reason the SortedMap causes kotlin to freak out a little :)
fun extensionFunctions(functions: Collection<KFunction>): Map<KClass, List<KFunction>> { fun extensionFunctions(functions: Collection<KFunction>): Map<KClass, List<KFunction>> {
val map = TreeMap<KClass, List<KFunction>>() val map = TreeMap<KClass, List<KFunction>>()
functions.filter{ it.extensionClass != null }.groupBy(map){ it.extensionClass.sure() } functions.filter{ it.extensionClass != null }.groupByTo(map){ it.extensionClass.sure() }
return map return map
} }
// TODO for some reason the SortedMap causes kotlin to freak out a little :) // TODO for some reason the SortedMap causes kotlin to freak out a little :)
fun extensionProperties(properties: Collection<KProperty>): Map<KClass, List<KProperty>> { fun extensionProperties(properties: Collection<KProperty>): Map<KClass, List<KProperty>> {
val map = TreeMap<KClass, List<KProperty>>() val map = TreeMap<KClass, List<KProperty>>()
properties.filter{ it.extensionClass != null }.groupBy(map){ it.extensionClass.sure() } properties.filter{ it.extensionClass != null }.groupByTo(map){ it.extensionClass.sure() }
return map return map
} }
@@ -801,7 +801,7 @@ class KPackage(model: KModel, val descriptor: NamespaceDescriptor,
} }
fun groupClassMap(): Map<String, List<KClass>> { fun groupClassMap(): Map<String, List<KClass>> {
return classes.groupBy(TreeMap<String, List<KClass>>()){it.group} return classes.groupByTo(TreeMap<String, List<KClass>>()){it.group}
} }
fun packageFunctions() = functions.filter{ it.extensionClass == null } fun packageFunctions() = functions.filter{ it.extensionClass == null }