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 函数是可迭代对象的扩展函数,有两个参数,第一个参数为初始值,第二个参数为操作函数。操作函数接受两个参数,第一个函数为初始值,第二个参数是可迭代对象的子元素,操作函数的返回值为初始值的类型。
举个小例子,我们将一个List拼接成以"、"分隔的字符串
val list = listOf("1","2","3")
list.foldRightIndexed("",{i,t,r ->
println("i:$i r:$r t:$t")
if (i == recipe.foods.size - 1) {
t+r
} else {
"$t、$r"
}
})
这里我们选择的是foldRightIndexed()
这个函数,这个方法与fold
的不同的是:Right表示集合迭代时从右(最后一个索引)开始,Indexed表示该函数的第二参数是由三个参数构成的,第一个参数为迭代的索引。
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{}
就可以完成这个功能.