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{}
就可以完成這個功能.