Kotlin在Android上的运用(四)

来源:互联网 发布:修复白苹果而不丢数据 编辑:程序博客网 时间:2024/06/01 07:43

13.Introduction

Kotlin提供了一系列的to方法将一个集合类型转换成另外一个集合类型。

这一部分的第一个任务很简单,根据提示就可以完成,关于任务就不必多说。

先说明一下第二部分所有任务的数据模型。这一部分所有的任务都是围绕一个商店(Shop)展开,商店有一个客户(Customer)列表。

客户具有姓名、城市和订单(Order)列表三个属性。

订单具有商品(Product)列表和是否已经发货两个属性。

商品具有名称和价格两个属性。

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}

第二部分所有的任务都是使用扩展函数的形式完成。

14.Filter Map

这个任务主要练习使用filter 和 map这两个方法。

filter

filter方法返回一个包含所有满足指定条件元素的列表。与之对应的还有filterNot,顾名思义就是返回一个包含所有不满足指定条件的元素列表。还有一个filterNotNull,返回所有不为null的元素列表。

回到我们的任务要求:返回指定城市所有客户的列表。使用filter方法就可以完成:

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

再精简一下:

// Return a list of the customers who live in the given cityfun Shop.getCustomersFrom(city: City) = customers.filter{it.city == city}map

map就是将指定的转换函数运用到原始集合的每一个元素,并返回一个转换后的集合。

任务要求返回所有客户所在城市的Set。这里我们需要使用map 和toSet两个方法:

// Return the set of cities the customers are fromfun Shop.getCitiesCustomersAreFrom() = customers.map { it.city }.toSet()

15.All Any and others Predicates

这个任务主要练习all ,any和count等几个方法。

all

第一个小任务是判断是否所有的客户都来自指定的城市。这需要使用Kotlin库提供的all方法。如果所有的元素都满足指定的条件那么all方法就返回true:

// Return true if all customers are from the given cityfun Shop.checkAllCustomersAreFrom(city: City): Boolean {    //return customers.filter { it.city != city }.isEmpty()    //return customers.filter{!it.isFrom(city)}.isEmpty()    return customers.all { it.isFrom(city) }}

当然也可以不使用all来完成,不过效率可能没有all高,因为all方法在遍历的过程中遇到第一个不满足条件的元素就返回结果(false):

// Return true if all customers are from the given cityfun Shop.checkAllCustomersAreFrom(city: City) = customers.filter{!it.isFrom(city)}.isEmpty()any

第二个小任务就是查询是否至少存在一个用户来自指定的城市。需要使用any方法,如果至少有一个元素满足指定的条件any就返回ture:

// Return true if there is at least one customer from the given cityfun Shop.hasCustomerFrom(city: City) = customers.any{it.city==city}count

第三个小任务计算来自指定城市的客户数量。需要使用count方法,count方法返回满足指定条件的元素数量。

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

firstOrNull

最后一个小任务,返回一个来自指定城市的客户,如果没有就返回null。需要使用firstOrNull方法,该方法返回第一个满足指定条件的元素,如果没有就返回null。和它相似的还有first,不过first是返回第一个满足指定条件的元素,如果没有元素满足指定条件则抛出异常NoSuchElementException。

// Return a customer who lives in the given city, or null if there is nonefun Shop.findAnyCustomerFrom(city: City) = customers.firstOrNull { it.city == city }

16.FlatMap

这个任务的两个小项都是练习使用flatmap方法。flatmap方法就是针对列表中的每一项根据指定的方法生成一个列表,最后将所有的列表拼接成一个列表返回。

第一个小项是要求返回一个客户所有已订购的产品,需要使用flatmap方法,遍历该用户所有的订单,然后将所有订单的产品拼接起来:

val Customer.orderedProducts: Set<Product> get() {    // Return all products ordered by customer    return orders.flatMap { it.products }.toSet()}

第二个小项是要求返回所有至少被一个客户订购过的商品集合。这个在第一个小任务的基础上再flatmap一次:

val Shop.allOrderedProducts: Set<Product> get() {    // Return all products that were ordered by at least one customer    return customers.flatMap { it.orderedProducts }.toSet()}

17.Max Min

第一个任务是返回商店中订单数目最多的一个客户。使用Kotlin库提供的max方法很好实现。max方法返回最大的一个元素,如果没有元素则返回null。对于自定义的对象,我们可以通过maxBy方法提供最大的评判标准,maxBy方法返回第一个满足指定评判标准的最大值。

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

第二个任务是要求返回一个客户所订购商品中价格最高的一个商品,使用flatmap 和 maxBy组合:

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

当然和max 和maxBy对应的还有min和minBy,只不过返回的是最小值。

18.Sort

Kotlin库提供了为元素排序的方法sorted。sorted方法会返回一个升序排序的列表,同样可以通过sortedBy指定排序的标准,按照指定的标准排序。

任务的要求返回一个客户列表,客户的顺序是根据订单的数量由低到高排列:

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

对于排序操作同样可以要求按照降序排序,两个方法分别是:sortedDescending和sortedByDescending。

还有另外一个操作方法就是反转reverse。

19.Sum

任务要求计算一个客户所有已订购商品的价格总和。使用Kotlin的sumBy方法就可以完成,sumBy将集合中所有元素按照指定的函数变换以后的结果累加。当然先要将所有的订单flatmap:

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.   return  orders.flatMap { it.products }.sumByDouble { it.price }}

20.GroupBy

groupBy方法返回一个根据指定条件分组好的map。任务要求是返回来自每一个城市的客户的map:

fun Shop.groupCustomersByCity(): Map<City, List<Customer>> {    // Return a map of the customers living in each city    return  customers.groupBy { it.city }}

21.Parition

任务要求返回所有未发货订单数目多于已发货订单的用户。

任务的范例中展示了怎么使用partition方法。partition方法会将原始的集合分成一对集合,这一对集合中第一个是满足指定条件的元素集合,第二个是不满足指定条件的集合。

这里我们先给Customer定义一个函数,判断该用户是否属于未发货订单大于已发货订单,处理方法就是使用partition方法将所有的订单分割,分割的条件就是该订单已经发货:

fun Customer.isMoreUndeliveredOrdersThanDelivered(): Boolean{    val(delivered, undelivered) = orders.partition { it.isDelivered }    return delivered.size < undelivered.size}

然后再对所有的客户进行筛选:

fun Shop.getCustomersWithMoreUndeliveredOrdersThanDelivered(): Set<Customer> {    // Return customers who have more undelivered orders than delivered    return customers.filter { it.isMoreUndeliveredOrdersThanDelivered() }.toSet()}

将这两个函数写到一起:

fun Shop.getCustomersWithMoreUndeliveredOrdersThanDelivered() =        customers.filter {            val(delivered, undelivered) = it.orders.partition { it.isDelivered }            undelivered.size > delivered.size         }.toSet()

22.Fold

任务要求返回每一个顾客都购买过的商品集合。

先来看一下fold方法,fold方法就是给定一个初始值,然后通过迭代对集合中的每一个元素执行指定的操作并将操作的结果累加。注意操作函数的两个参数分别是累加结果和集合的元素。

直接看fold函数的定义吧:

public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (R, T) -> R): R {    var accumulator = initial    for (element in this) accumulator = operation(accumulator, element)    return accumulator}

回到我们的任务,使用fold函数,由于任务要求返回所有客户都已经订购的商品,所以初始值设置为所有已经订购的商品,然后用这个初始值去和每一个客户已订购的商品求交集,最终的结果就是所有用户都已经购买过的商品:

fun Shop.getSetOfProductsOrderedByEveryCustomer(): Set<Product> {    // Return the set of products ordered by every customer    return customers.fold(allOrderedProducts, {        orderedByAll, customer -> orderedByAll.intersect(customer.orderedProducts)    })}

这里使用了Kotlin提供的intersect方法。

23.CompoundTasks

终于快结束这一部分的任务了。这一部分包括几个小任务,完成任务需要用到前面所练习的各种方法的组合。

来看第一个小任务:返回所有购买了指定商品的客户列表。首先给Customer扩展一个方法,判断他是否已经订购指定的商品,使用any方法:

fun Customer.hasOrderedProduct(product: Product) = orders.any{it.products.contains(product)}
然后根据他是否已经订购指定商品来做过滤:

fun Shop.getCustomersWhoOrderedProduct(product: Product): Set<Customer> {    // Return the set of customers who ordered the specified product    return customers.filter { it.hasOrderedProduct(product) }.toSet()}

第二个小任务:查找某个用户所有已发货的商品中最昂贵的商品。首先过滤出已发货的订单,然后flatmap,再求最大值:

fun Customer.getMostExpensiveDeliveredProduct(): Product? {    // Return the most expensive product among all delivered products    // (use the Order.isDelivered flag)    return orders.filter { it.isDelivered }.flatMap { it.products }.maxBy { it.price }}

第三个小任务:查找指定商品被购买的次数。首先获取到客户所有已订购的商品列表,使用flatmap:

fun Customer.getOrderedProducts() = orders.flatMap { it.products }
然后继续flatmap,将所有客户已经订购的商品组成一个列表,最后再count:

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.getOrderedProducts() }.count{it == product}}

将两个函数组合到一起:

    // Return the number of times the given product was ordered.    // Note: a customer may order the same product for several times.fun Shop.getNumberOfTimesProductWasOrdered(product: Product) = customers.flatMap { it.orders.flatMap { it.products } }.count{it == product}

24.Extensions On Collections

最后一个任务,就是实现 _24_JavaCode.doSomethingStrangeWithCollection函数的功能。所以先读懂_24_JavaCode.doSomethingStrangeWithCollection的意图:

public class _24_JavaCode extends JavaCode {    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;    }}

将一个字符串集合按照长度分组,放入一个map中
求出map中所有元素(String List)的最大长度
根据步骤2的结果,返回map中字符串数目最多的那一组
Kotlin的实现,首先根据长度分组,然后求最大值:

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

精简一下:

fun doSomethingStrangeWithCollection(collection: Collection<String>) =        collection.groupBy { it.length }.values.maxBy { it.size }
原创粉丝点击