Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【用 Kotlin 写 Android】Kotlin Koans 深入分析讲解(中) #29

Open
renyuzhuo opened this issue Apr 10, 2018 · 0 comments
Open
Assignees
Labels
Blog TextBlog 微信小程序 Blog

Comments

@renyuzhuo
Copy link
Owner

继续接着上一篇我们介绍的,我们继续深入学习 Kotlin Koans。

Task 20:Introduction

接下来的 Task,都是围绕集合展开的,Kotlin 的集合和 Java 的集合差不多,不过 Kotlin 扩展了许多有用的方法。我们先看一下 Show 类的定义:

data class Shop(val name: String, val customers: List<Customer>)

data class Customer(val name: String, val city: City, val orders: List<Order>) {
    override fun toString() = "$name from ${city.name}"
}

data class Order(val products: List<Product>, val isDelivered: Boolean)

data class Product(val name: String, val price: Double) {
    override fun toString() = "'$name' for $price"
}

data class City(val name: String) {
    override fun toString() = name
}

20:Introduction

比较容易,直接用 Shop 中的 customers 转换成 Set 就可以了:

答案

Task 21:Filter; map

Filter; map

其中我们可以看到 map 方法是:对于给定的规则,返回 List:

/**
 * Returns a list containing the results of applying the given [transform] function
 * to each element in the original collection.
 */
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

/**
 * Applies the given [transform] function to each element of the original collection
 * and appends the results to the given [destination].
 */
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
    for (item in this)
        destination.add(transform(item))
    return destination
}

对于 filter 方法是:返回符合给定规则的 List,规则用于判定该元素是否符合要求,规则返回值为 Boolean

/**
 * Returns a list containing only elements matching the given [predicate].
 */
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

/**
 * Appends all elements matching the given [predicate] to the given [destination].
 */
public inline fun <T, C : MutableCollection<in T>> Iterable<T>.filterTo(destination: C, predicate: (T) -> Boolean): C {
    for (element in this) if (predicate(element)) destination.add(element)
    return destination
}

答案

Task 22:All, Any and other predicates

All, Any and other predicates

有了上面的经验,这里的问题就好解决了:

答案

根据名称,我们其实可以很容易猜到是干什么,但是我们这里还是要看看其中具体是怎么实现的:

/**
 * Returns `true` if all elements match the given [predicate].
 */
public inline fun <T> Iterable<T>.all(predicate: (T) -> Boolean): Boolean {
    if (this is Collection && isEmpty()) return true
    // 有一个不符合条件,就返回 false
    for (element in this) if (!predicate(element)) return false
    return true
}

/**
 * Returns `true` if at least one element matches the given [predicate].
 */
public inline fun <T> Iterable<T>.any(predicate: (T) -> Boolean): Boolean {
    if (this is Collection && isEmpty()) return false
    // 有符合条件的,就返回 true
    for (element in this) if (predicate(element)) return true
    return false
}

/**
 * Returns the number of elements matching the given [predicate].
 */
public inline fun <T> Iterable<T>.count(predicate: (T) -> Boolean): Int {
    if (this is Collection && isEmpty()) return 0
    var count = 0
    // 有符合条件的,计数加一,最后返回计数
    for (element in this) if (predicate(element)) count++
    return count
}

/**
 * Returns the first element matching the given [predicate], or `null` if no such element was found.
 */
@kotlin.internal.InlineOnly
public inline fun <T> Iterable<T>.find(predicate: (T) -> Boolean): T? {
    return firstOrNull(predicate)
}
/**
 * Returns the first element matching the given [predicate], or `null` if element was not found.
 */
public inline fun <T> Iterable<T>.firstOrNull(predicate: (T) -> Boolean): T? {
    // 有符合条件的,返回符合条件的这一项
    for (element in this) if (predicate(element)) return element
    return null
}

Task 23:FlatMap

FlatMap

FlatMap 对集合中的元素去重组成新的集合:

/**
 * Returns a single list of all elements yielded from results of [transform] function being invoked on each element of original collection.
 */
public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
    return flatMapTo(ArrayList<R>(), transform)
}
/**
 * Appends all elements yielded from results of [transform] function being invoked on each element of original collection, to the given [destination].
 */
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
    // 遍历集合中元素,把元素的去重后重组成 List 返回
    for (element in this) {
        val list = transform(element)
        destination.addAll(list)
    }
    return destination
}

答案

Task 24:Max; min

最大最小的查找是比较常用的操作,结合前面的 FlatMap,可以解决此问题:

答案

其中我们看看 max 是如何实现的:

/**
 * Returns the first element yielding the largest value of the given function or `null` if there are no elements.
 */
public inline fun <T, R : Comparable<R>> Iterable<T>.maxBy(selector: (T) -> R): T? {
    val iterator = iterator()
    if (!iterator.hasNext()) return null
    var maxElem = iterator.next()
    var maxValue = selector(maxElem)
    // 简单粗暴遍历查找符合条件的最大的一项,是稳定的
    while (iterator.hasNext()) {
        val e = iterator.next()
        val v = selector(e)
        if (maxValue < v) {
            maxElem = e
            maxValue = v
        }
    }
    return maxElem
}

Task 24:Sort

Sort

排序:

答案

看似简单,不过似乎有没那么简单:

/**
 * Returns a list of all elements sorted according to natural sort order of the value returned by specified [selector] function.
 */
public inline fun <T, R : Comparable<R>> Iterable<T>.sortedBy(crossinline selector: (T) -> R?): List<T> {
    return sortedWith(compareBy(selector))
}

/**
 * Returns a list of all elements sorted according to the specified [comparator].
 */
public fun <T> Iterable<T>.sortedWith(comparator: Comparator<in T>): List<T> {
    if (this is Collection) {
       if (size <= 1) return this.toList()
       @Suppress("UNCHECKED_CAST")
       return (toTypedArray<Any?>() as Array<T>).apply { sortWith(comparator) }.asList()
    }
    return toMutableList().apply { sortWith(comparator) }
}

/**
 * Creates a comparator using the function to transform value to a [Comparable] instance for comparison.
 */
@kotlin.internal.InlineOnly
public inline fun <T> compareBy(crossinline selector: (T) -> Comparable<*>?): Comparator<T> =
        Comparator { a, b -> compareValuesBy(a, b, selector) }

/**
 * Compares two values using the specified [selector] function to calculate the result of the comparison.
 * The function is applied to the given values [a] and [b] and return [Comparable] objects.
 * The result of comparison of these [Comparable] instances is returned.
 */
@kotlin.internal.InlineOnly
public inline fun <T> compareValuesBy(a: T, b: T, selector: (T) -> Comparable<*>?): Int {
    return compareValues(selector(a), selector(b))
}

/**
 * Compares two nullable [Comparable] values. Null is considered less than any value.
 */
public fun <T : Comparable<*>> compareValues(a: T?, b: T?): Int {
    if (a === b) return 0
    if (a == null) return -1
    if (b == null) return 1

    @Suppress("UNCHECKED_CAST")
    return (a as Comparable<Any>).compareTo(b)
}

/**
 * Returns a list of all elements sorted according to the specified [comparator].
 */
public fun <T> Iterable<T>.sortedWith(comparator: Comparator<in T>): List<T> {
    if (this is Collection) {
       if (size <= 1) return this.toList()
       @Suppress("UNCHECKED_CAST")
       return (toTypedArray<Any?>() as Array<T>).apply { sortWith(comparator) }.asList()
    }
    return toMutableList().apply { sortWith(comparator) }
}

Task 25:Sum

Sum

求和:

答案

/**
 * Returns the sum of all values produced by [selector] function applied to each element in the collection.
 */
public inline fun <T> Iterable<T>.sumByDouble(selector: (T) -> Double): Double {
    var sum: Double = 0.0
    // 遍历并相加
    for (element in this) {
        sum += selector(element)
    }
    return sum
}

Task 26:Group By

Group By

分组:

答案

实现方法:

/**
 * Groups elements of the original collection by the key returned by the given [keySelector] function
 * applied to each element and returns a map where each group key is associated with a list of corresponding elements.
 *
 * The returned map preserves the entry iteration order of the keys produced from the original collection.
 *
 * @sample samples.collections.Collections.Transformations.groupBy
 */
public inline fun <T, K> Iterable<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>> {
    return groupByTo(LinkedHashMap<K, MutableList<T>>(), keySelector)
}

/**
 * Groups elements of the original collection by the key returned by the given [keySelector] function
 * applied to each element and puts to the [destination] map each group key associated with a list of corresponding elements.
 *
 * @return The [destination] map.
 *
 * @sample samples.collections.Collections.Transformations.groupBy
 */
public inline fun <T, K, M : MutableMap<in K, MutableList<T>>> Iterable<T>.groupByTo(destination: M, keySelector: (T) -> K): M {
    for (element in this) {
        val key = keySelector(element)
        // 将新数据添加到 Map 中,如果以前有 Key,添加,否则创建后添加
        val list = destination.getOrPut(key) { ArrayList<T>() }
        list.add(element)
    }
    return destination
}

/**
 * Returns the value for the given key. If the key is not found in the map, calls the [defaultValue] function,
 * puts its result into the map under the given key and returns it.
 *
 * @sample samples.collections.Maps.Usage.getOrPut
 */
public inline fun <K, V> MutableMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
    val value = get(key)
    // 在 Map 中根据 Key 判断是否可以找到 Value,如果找不到,在这个 Map 中创建一条
    return if (value == null) {
        val answer = defaultValue()
        put(key, answer)
        answer
    } else {
        value
    }
}

Task 27:Partition

Partition

区分(满足条件和不满住条件):

答案 1

答案 2

/**
 * Splits the original collection into pair of lists,
 * where *first* list contains elements for which [predicate] yielded `true`,
 * while *second* list contains elements for which [predicate] yielded `false`.
 */
public inline fun <T> Iterable<T>.partition(predicate: (T) -> Boolean): Pair<List<T>, List<T>> {
    val first = ArrayList<T>()
    val second = ArrayList<T>()
    // 判断是否满足条件,分别放到第一个第二个参数中
    for (element in this) {
        if (predicate(element)) {
            first.add(element)
        } else {
            second.add(element)
        }
    }
    return Pair(first, second)
}

Task 28:Fold

Fold

聚合(Fold),思路是:找出所有商品,将这些商品依次和每一个用户买过的商品做交集,最后剩下的商品就是所有用户都购买了的商品:

答案

/**
 * Accumulates value starting with [initial] value and applying [operation] from left to right to current accumulator value and each element.
 */
public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) -> R): R {
    var accumulator = initial
    for (element in this) accumulator = operation(accumulator, element)
    return accumulator
}

小结

到这里,我们完成了集合类相关的测试,我们可以看到,集合的基本数据结构,Kotlin 和 Java 区别不大,但是 Kotlin 扩展了集合的方法,这些方法的灵活应用,可以基本满足平时集合相关的操作。要想更灵活的应用,需要我们多加练习,更好的去熟悉。


如果有一天你觉得过的舒服了,你就要小心了!欢迎关注我的公众号:我是任玉琢
qrcode_for_gh_45402a07f7d9_258

@RWebRTC RWebRTC added the Blog label Apr 10, 2018
@renyuzhuo renyuzhuo added the TextBlog 微信小程序 Blog label Aug 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Blog TextBlog 微信小程序 Blog
Projects
None yet
Development

No branches or pull requests

2 participants