Kotlin Koans 學習筆記 —— Unit 2

Kotlin Koans 學習筆記 —— Unit 1

Kotlin Koans第二單元講的主要是集合在Kotlin中的各種高級操作。

13 介紹

fun Shop.getSetOfCustomers(): Set<Customer> {
    // Return a set containing all the customers of this shop
    return this.customers.toSet()  //將 List 轉換成 Set
}

在 Kotlin 中實現了集合類之間轉換的各種擴展函數,我們只需要調用 toXXX 就可以簡單地將某一個集合轉換成另一個!

14 FilterMap 過濾與映射

fun Shop.getCitiesCustomersAreFrom(): Set<City> {
    // Return the set of cities the customers are from
    return this.customers.map {
        it.city
    }.toSet()
}

fun Shop.getCustomersFrom(city: City): List<Customer> {
    // Return a list of the customers who live in the given city
    return this.customers.filter {
        it.city == city
    }
}

fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> map 映射函數,將一個可d迭代對象按照傳入的轉換函數變成一個 List 對象。

fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> filter 過濾函數,將一個可迭代對象根據傳入的判斷函數進行過濾,並將結果放在一個 List 對象中。

15 AllAnyAndOtherPredicates 判斷函數

fun Shop.checkAllCustomersAreFrom(city: City): Boolean {
    // Return true if all customers are from the given city
    return this.customers.all {
        it.isFrom(city)
    }
}

fun Shop.hasCustomerFrom(city: City): Boolean {
    // Return true if there is at least one customer from the given city
    return this.customers.any { it.isFrom(city) }
}

fun Shop.countCustomersFrom(city: City): Int {
    // Return the number of customers from the given city
    return this.customers.count { it.isFrom(city) }
}

fun Shop.findFirstCustomerFrom(city: City): Customer? {
    // Return the first customer who lives in the given city, or null if there is none
    return this.customers.firstOrNull { it.isFrom(city) }
}

全局判斷函數:all {(T)->Boolean}返回 boolean 全部滿足才返回 true
等同於list.size == list.filter{(T)->Boolean}.size

包含判斷函數:any {(T)->Boolean} 返回 boolean 只要滿足lambda即返回 true
等同於:list.fliter{(T)->Boolean}.size>0

判斷計數函數 count{(T)->Boolean} 返回滿足條件的子集數量
等同於list.fliter{(T)->Boolean}.size

判斷首項函數:firstOrNull{(T)->Boolean} 返回子集中第一個滿足條件的項( T 或者 null)
等同於

var r = list.filter{}
return if (r.size>0) r.get(0) else null

16 FlatMap 平鋪映射函數

val Customer.orderedProducts: Set<Product> get() {
    // Return all products this customer has ordered
    //返回用戶全部訂單中所有的商品種類
    return orders.flatMap {
        it.products
    }.toSet()
}

val Shop.allOrderedProducts: Set<Product> get() {
    // Return all products that were ordered by at least one customer
    //返回商店中全部的至少被一位用戶下單過的商品
   customers.flatMap {
        it.orders
    }.flatMap {
        it.products
    }.toSet()

    return customers.flatMap {
        it.orderedProducts
    }.toSet()
}

老規矩先看函數簽名 fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R>,該函數是對 Iterable 接口的擴展,flatMap 函數接受一個 transform 函數,這個函數的簽名爲傳入 T 返回 Iterable。

flatMap 看起來與 map 函數很像,最終實現的都是講一個可序列對象轉換成一個 List 對象。不同的是 flatMap 是一對多映射,map 函數是一對一映射。

17 MaxMin 最大最小

fun Shop.getCustomerWithMaximumNumberOfOrders(): Customer? {
    // Return a customer whose order count is the highest among all customers
    return this.customers.maxBy { it.orders.size }
}

fun Customer.getMostExpensiveOrderedProduct(): Product? {
    // Return the most expensive product which has been ordered
    return this.orders.flatMap {
        it.products
    }.maxBy {
        it.price
    }
}

取最大值函數:max()maxBy{} 根據傳入的選擇器找出集合中最大的成員
fun <T : Comparable<T>> Iterable<T>.max(): T? max 函數簽名
fun <T, R : Comparable<R>> Iterable<T>.maxBy(selector: (T) -> R): T? maxBy 函數簽名

18 排序函數

fun Shop.getCustomersSortedByNumberOfOrders(): List<Customer> {
    // Return a list of customers, sorted by the ascending number of orders they made
    return this.customers.sortedBy {
        it.orders.size
    }
}

排序函數:sortedBy{} 根據傳入的選擇器升序排列

19 求和函數

//三種求和實現方法
fun Customer.getTotalOrderPrice(): Double {
    // Return the sum of prices of all products that a customer has ordered.
    // Note: a customer may order the same product for several times.
    //使用求和函數
    orders.flatMap {
        it.products
    }.sumByDouble {
        it.price
    }
	//使用fold函數
    orders.flatMap { it.products }.fold(0.0,{acc, product ->
            acc+product.price
    })
    //使用 forEach函數
    var result = 0.0
    orders.flatMap { it.products }.forEach {
        result+=it.price
    }
    return  result
}

求和函數:sum()返回Int、 sumBy{}返回 Int、 sumByDouble{} 返回 Double

20 分組函數

fun Shop.groupCustomersByCity(): Map<City, List<Customer>> {
    // Return a map of the customers living in each city
    //不使用groupBy函數的寫法
    val map = mutableMapOf<City,List<Customer>>()
    val citys = this.customers.map {
        it.city
    }.toSet().map {
        map.put(it, this.getCustomersFrom(it))
    }

    return this.customers.groupBy { it.city }
}

分組函數 groupBy{} 按照傳入的選擇器將集合對象分組返回Map<K, List<T>>

21 Partition 劃分函數

fun Shop.getCustomersWithMoreUndeliveredOrdersThanDelivered(): Set<Customer> {
    // Return customers who have more undelivered orders than delivered
   return  this.customers.filter {
       val (delivered,undelivered) = it.orders.partition { it.isDelivered }
       undelivered.size>delivered.size
   }.toSet()
}

fun <T> Iterable<T>.partition(predicate: (T) -> Boolean): Pair<List<T>, List<T>> 根據傳入的判斷函數,將可迭代對象劃分爲滿足條件與不滿足條件兩個 List 對象,然後放入 Pair 對象中,其中 first 爲滿足判斷函數,second 爲不滿足判斷函數。

22 Fold 摺疊函數

fun Shop.getSetOfProductsOrderedByEachCustomer(): Set<Product> {
    // Return the set of products that were ordered by each of the customers
    //找到商店中每一個用戶都下單的商品
    allOrderedProducts.filter { p ->
        customers.all {
            it.orders.flatMap {
                it.products
            }.any {
                it == p
            }
        }
    }.toSet()

    return customers.fold(allOrderedProducts, { orderedByAll, customer ->
        //第一次調用該函數時傳入值爲fold函數的第一個參數 全部被下單的產品集合
        orderedByAll.intersect( //交集運算
                customer.orders.flatMap {
                    it.products
                }.toSet() //傳入的用戶的全部產品的集合
        )
    })
}

老規矩看源碼:

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
}

這個函數還是很好理解的,fold 函數是可迭代對象的擴展函數,有兩個參數,第一個參數爲初始值,第二個參數爲操作函數。操作函數接受兩個參數,第一個函數爲初始值,第二個參數是可迭代對象的子元素,操作函數的返回值爲初始值的類型。

23 CompoundTask

fun Shop.getCustomersWhoOrderedProduct(product: Product): Set<Customer> {
    // Return the set of customers who ordered the specified product
    //根據傳入的商品返回全部訂購該商品的用戶
    return customers.filter {
        it.orders.flatMap {
            it.products
        }.any {
            it==product
        }
    }.toSet()
}

fun Customer.getMostExpensiveDeliveredProduct(): Product? {
    // Return the most expensive product among all delivered products
    //返回已經完成交付的最貴的商品
    // (use the Order.isDelivered flag)
    return this.orders.filter {
        it.isDelivered
    }.flatMap {
        it.products
    }.maxBy {
        it.price
    }
}

fun Shop.getNumberOfTimesProductWasOrdered(product: Product): Int {
    // Return the number of times the given product was ordered.
    // Note: a customer may order the same product for several times.
    //根據傳入的商品返回該商品被訂購的次數,注意一個客戶可能訂購同一個商品數次
    return customers.flatMap {
        it.orders
    }.flatMap {
        it.products
    }.count {
        it==product
    }
}

24 集合的擴展

fun doSomethingStrangeWithCollection(collection: Collection<String>): Collection<String>? {
    val groupsByLength = collection.groupBy { s -> s.length }
    return groupsByLength.values.maxBy { group -> group.size }
}

這個任務的要求是仿照 _24_JavaCode.doSomethingStrangeWithCollection 這個函數,用 kotlin 書寫完成相同的功能。

public Collection<String> doSomethingStrangeWithCollection(Collection<String> collection) {
    Map<Integer, List<String>> groupsByLength = Maps.newHashMap();
    for (String s : collection) {
        List<String> strings = groupsByLength.get(s.length());
        if (strings == null) {
            strings = Lists.newArrayList();
            groupsByLength.put(s.length(), strings);
        }
        strings.add(s);
    }
    int maximumSizeOfGroup = 0;
    for (List<String> group : groupsByLength.values()) {
        if (group.size() > maximumSizeOfGroup) {
            maximumSizeOfGroup = group.size();
        }
    }
    for (List<String> group : groupsByLength.values()) {
        if (group.size() == maximumSizeOfGroup) {
            return group;
        }
    }
    return null;
}

原 Java 函數實現的功能是,將傳入的 Collection<String> 根據字符串的長度分組,然後返回數量最多的那個。在 Kotlin 中只需要適當使用 groupBy{} 函數與 maxBy{} 就可以完成這個功能.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章