Kotlin基础知识(七)——集合的函数API

864 阅读3分钟

一、基础:filter和map

***filtermap***函数形成了集合操作的基础,很多集合操做都是借助它们来表达的。

  • ***filter***示例一
>>> val list = listOf{1,2,3,4}
// 只能偶数留下来
>>> println(list.filter { it % 2 == 0 }
[2,4]

上面的结果是一个新的集合,它只包含输入集合中某些满足判断式的元素。

  • ***filter***示例二
>>> val people = listOf(Person("Alice", 29), Person("Bob", 31))
>>> println(people.filter { it.age > 30 }
[Person(name=Bob, age=31)]

map函数对集合中的每一个元素应用给定的函数并把结果收集到一个新集合

  • ***map***示例一
>>> val list = listOf(1,2,3,4)
>>> println(list.map{ it * it })
[1,4,9,16]

二、“all”、“any”、“count”和“find”:对集合应用判断式

Kotlin中

  • allany:检查集合中的所有元素是否都符合某个条件(或者它的变种,是否存在符合的元素)。
  • ***count***函数检查有多少元素满足判断式。
  • ***find***函数返回第一个符合条件的元素。
// 判断式canBeInClub27
val canBeInClue27 = { p: Person -> p.age <= 27 }

// 是否所有元素都满足判断式感兴趣,应该使用all函数
>>> val people = listOf(Person("Alice", 27), Person("Bob", 31))
>>> println(people.all(canBeInClub27))
false

// 检查集合中是否至少存在一个匹配的元素,那就用any
>>> println(people.any(canBeInClue27))
true

注意

!all(“不是所有”)加上某个条件,可以用***any***加上这个条件的取反来替代,反之亦然。


***count***函数统计有多少元素满足了判断式

  • ***count***示例
>>> val people = listOf(Person("Alice", 27), Person("Bob", 31))
>>> println(people.count(canBeInClub27))
1

使用正确的函数完成工作:“count” VS “size”

count方法容易被遗忘,然后通过过滤集合之后再去大小来实现它:

`println(people.filter(canBeInClub27).size)

在这种情况下,一个中间集合会被创建并用来存储所有满足判断式的元素。而另一方面, **count方法只是跟踪匹配元素的数量,不关心元素本身,所以更高效。 一般规则:尝试找到合适你需求的最合适的操作。


***find***函数找到第一个满足判断式的元素

  • ***find***示例
>>> val people = listOf(Person("Alice", 27), Person("Bob", 31))
>>> println(people.find(canBeInClub27))
Person(name=Alice, age=27)

若有多个匹配的元素就返回其中第一个元素;或者返回null,如果没有一个元素能满足判断式。find还有一个同义方法firstOrNull,可以使用这个方法更清楚地表述你的意图。

三、groupBy:把列表转换成分组的map

groupBy:把所有元素按照不同的特征划分成不同的分组。

  • ***groupBy***示例
>>> val people = listOf(Person("Alice", 27), Person("Bob", 27), Person("Cartol", 31))
// 该操作的结果是一个map,是元素分组依据的键和元素分组之间的映射
>>> println(people.groupBy{ it.age })
{29=[Person(name=Bob, age=29)],
 30=[Person(name=Alice, age=31)], Person(name=Carol, age=31)]}

groupBy的底层结构:每一个分组都是存储在一个列表中,结果的类型就是Map<Int, List<Person>>。可以使用mapKeysmapValues这样的函数对这个map做进一步的修改。

四、flatMap和flatten:处理嵌套集合中的元素

假设使用***Book***类表示:

// 定义
class Book(val title: String, val anthors: List<String>)
// 包含撰写“books”集合中书籍的所有作者的set
books.flatMap { it.authors }.toSet()

***flatMap***函数做了两件事:

  • 1.根据作为实参给定的函数对集合中的每个元素做变换(或者说映射);
  • 2.把多个列表合并(或者说平铺)成一个列表。
>>> val strings = listOf("abc", "def")
>>> println(strings.flatMap { it.toList() }
[a,b,c,d,e,f]

***flatten***函数:不需要做任何变换,只是需要平铺一个集合:listOfLists.flatten()

编写关于集合的代码时,一般的建议是:想一想这个操作如何用一个通用的变换来表达,然后寻找能执行这种变换的库函数。