Kotlin 集合操作(读书笔记)

第7章 集合类

在 Java 类库中有一套相当完整的容器集合类来持有对象。Kotiin 没有去重复造轮子,而是在 Java 类库的基础上进行了改造和扩展,引入了不可变集合类,同时扩展了大量方便实用的功能,这些功能的 API 都在 kotlin.collections 包下面。
另外,在 Kotlin 的集合类中不仅仅能持有普通对象,而且能够持有函数类型的变量。

val funlist: List<(Int) -> Boolean> = listOf({
      it -> it % 2 == 0 },
 {
      it -> it % 2 == 1 })

其中, (Int)->Boolean是一个从Int 映射到Boolean的函数。而这个时候,我们可以在代码里选择调用哪个函数:

 	val list = listOf(1, 2, 3, 4, 5, 6, 7)
    val filter1 = list.filter(funlist[0])
    val filter2 = list.filter(funlist[1])
    println("filter1==$filter1")
    println("filter2==$filter2")
    //传入第1个函数funlist[O],返回[2, 4, 6]
    //传入第2个函数funlist[1],返回[1,3, 5, 7]

7.1 集合类概述

集合类存放的都是对象的引用,而非对象本身,我们通常说的集合中的对象指的是集合中对象的引用( reference )。

Kotlin 的集合类分为:可变集合类( Mutable)与不可变集合类( Immutable) 。

7.1.1 常用的 3 种集合类

集合类主要有3种: List(列表)、Set(集)和Map(映射)
Kotlin 集合操作(读书笔记)_第1张图片

  • List 容器中的元素以线性方式存储,集合中可以存放重复对象。列表中的元素是有序地排列
  • Set集容器的元素无序、不重复
  • Map 映射中持有的是 “键值对”对象,每一个对象都包含一对键值 K-V 对象

从数据结构的本质上来看,其实List中的下标就是Key,只不过Key是有序 的Int类型,所以说List也可以说是一种特殊的Map数据结构。 而Set也是Key为Int类 型,但是 Value 值是不能重复的特殊 Map。

7.1.2 Katlin 集合类继承层次

Kotlin 集合操作(读书笔记)_第2张图片
各个接口说明如下:
Kotlin 集合操作(读书笔记)_第3张图片

7.2 不可交集合类

List 列表分为只读不可变的 List 和可变 MutableList (可写入、删除数据)。List列表的类型层次结构如图
Kotlin 集合操作(读书笔记)_第4张图片
Set 集也分为不可变 Set 和可变 MutableSet (可写入、删除数据)。 Set 集合的类型层次结构如图
Kotlin 集合操作(读书笔记)_第5张图片
Kotlin 中的 Map 与 List、Set 一样,Map 也分为只读 Map 和可变 MutableMap (可写入、 删除数据)。 Map类型的层次结构如图
Kotlin 集合操作(读书笔记)_第6张图片

7.3 创建集合类

Kotiin 中分别使用 listOf()、setOf()、mapOf() 函数创建不可变的 List列表容器、Set集容器、Map 映射容器。使用 mutableListOf()、 mutableSetO叹)、mutableMapOf()函数来创建可变的 MutableList 列表容器、MutableSet 集容器、MutableMap 映射容器,分别如图:
Kotlin 集合操作(读书笔记)_第7张图片
代码

//创建不可变 List
val list = listOf(1, 2, 3, 4, 5, 6, 7)
//创建可变MutableList
val mutableList = mutableListOf(”a”,”b”,”c”)
//创建不可变 Set
val set = setOf(1, 2, 3, 4, 5, 6, 7)
//创建可变 MutableSet
val mutableSet = mutableSetOf("a","b","c")
//创建不可变 Map
val map = mapOf(1 to "a",2 to "b",3 to "c")
//创建可变 MutableMap
val mutableMap = mutableMapOf(1 to "X",2 to "Y",3 to "Z")

如果创建没有元素的空 List,使用 listOf()即可。不过这个时候,变量的类型不能省略,需要显式声明 ,否则会报错

val emptyList : List<Int> = listOf() //显式声明 List 的元素-类型为 Int
val emptySet : Set<Int> = setOf() //显式声明 Set 的元素类型为 Int
val emptyMap: Map<Int, String>= mapOf(}//显式声明Map的元素类型为Int, String键值对

7.4 遍历集合中的元素

List、Set 类继承了 Iterable 接口,里面扩展了 forEach 函数来送代遍历元素;同样,Map 接口中也扩展了 forEach 函数来送代遍历元素。

list.forEach {
     		//List 中的 forEach
	println(it)
}
set.forEach {
     		//Set 中的 forEach
	println(it)
}
map.forEach {
     		//Map 中的 forEach
	println(”K= ${
     it.key}, V= ${
     it.value}") //Map里面的对象是Map.Entry
}

forEach() 函数签名如下 :

public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit
public inline fun <K, V> Map<out K, V>.forEach(action : (Map.Entry<K, V>)-> Unit) : Unit

在 Iterable 和 Map 中, forEach 函数都是一个内联 inline 函数
在迭代遍历元素的时候访问 index 下标,在 List 和 Set 中可以使用 下面的 forEachlndexed 函数

//带下标index来遍历 List
list.forEachindexed {
      index, value ->
	println (” list index = ${
     index} , value = ${
     value})
}
//带下标 index 来遍历 Set
set.forEachindexed {
      index, value ->
	println (” set index = ${
     index} , value = ${
     value})
}	

其中,第 1 个参数是 index,第 2 个参数是 value
forEachlndexed 函数签名如下 :

public inline fun <T> Iterable<T> .forEachindexed(action : (index : Int , T)-> Unit): Unit

Map 的元素是 Entry 类型,由 entries属性持有

val entries : Set<Entry<K, V>>

这个 Entry类型定义如下:

public interface Entry<out K, out V> {
     
	public val key: K //键值对的Key
	public val value: V //键值对的Value
}

我们可以直接访问 entries 属性获取该 Map 中的所有键/值对的 Set。 代码示例如下:

>>> val map= mapOf(”x” to 1,”Y” to 2, ”z" to 3) //声明并初始化一个Map
>>> map
{
     x=1 , y=2, z=3}
>>> map.entries
[x=1, y=2, z=3]

这样就可以遍历这个 Entry 的 Set 了 :

//遍历 entries 中的元素
>>> map .entries . forEach ({
     println (”key=+ it . key + ” value=+ it.value)})
key=x value=1
key=y value=2
key=z value=3

7.5 映射函数

使用 map 函数,可以把集合中的元素依次使用给定的转换函数进行映射操作,元素映射之后的新值会存入一个新的集合中,并返回这个新集合。
Kotlin 集合操作(读书笔记)_第8张图片
在 List、 Set 继承的 Iterable 接口和 Map 接口中,都提供了这个 m叩函数。使用 map 函数的代码示例如下 :

val list = listOf(1, 2, 3, 4, 5, 6, 7)//声明并初始化一个 List
val set = setOf(1, 2, 3, 4, 5, 6, 7)//声明并初始化一个 Set
val map = mapOf(1 to "a"2 to "b", 3 to "c")//声明并初始化一个Map
//map函数对每个元素进行乘方操作,返回[1, 4, 9, 16, 25, 36, 49] 
list.map {
      it *it }
//map 函数对每个元素进行加 1操作,返回[2, 3, 4, 5, 6, 7, 8] 
set.map{
      it + 1 } 
//map 函数对每个元素后加上字符$,返回[a$,b$, c$]
map .map{
      it.value +"$" } 

map 函数的签名如下 :

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R) : List<R>
public inline fun <K, V, R> Map<out K, V> .map (transform : (Map.Entry<K, V>)> R) : List<R>

这里的 R 类型是映射之后的数据类型,我们也可以传入一个 List:

val strlist = listOf("a","b","c")
//map 函数 , 每个元素 it 映射之后返回一个List,这个List 中有 4 个元素,分别是 it+1,
//it+2,it+3,it+4
strlist.map {
      it -> listOf(it + 1, it + 2, it + 3, it + 4) }
//返回结果如下 :
[[a1, a2, a3, a4], [b1, b2, b3, b4] , [c1, c2, c3, c4]] //嵌套 List

Kotlin 中还提供了 一个 flatten()函数,效果是把嵌套的 List 结构“平铺”,变成一层 的 结构,代码示例如下 :

strlist.map {
      it 一> listOf(it + 1, it+ 2, it+ 3, it + 4) }.flatten()
//输出如下 :
[a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4]

flatMap 函数是 map 和 flat两个函数的“复合逻辑”,代码如下 :

strlist.flatMap {
      it -> listOf(it + 1, it + 2, it + 3, it + 4) }

输出同上面铺开的形式

7.6 过滤函数

首先,有一个 Student 对象,使用数据类来声明如下 :

data class Student (var id : Long, var name: String , var age : Int, var score :Int) {
     
	override fun toString() : String {
      //覆盖写 toString()函数
		return "Student(id=$id, name='$name', age=$age, score=$score)"
	}
}

创建一个持有 Student 对象 的 List:

//创建一个持有 Student对象 List 
val studentList = listOf( 
	Student(l,”Jack”, 18, 90) ,
	Student(2,”Rose”, 17, 80) ,
	Student(3,”Alice”, 16, 70)
}

这个时候,如果我们想要过滤出年龄大于等于 18 岁的学生,代码可以这样写 :

//过滤出 studentList 中年龄大于等于 18 岁的Student 对象
studentList.filter{
     it.age >= 18 } 

输出如下:

[Student(id=1, name='Jack', age=18, score=90)]

如果想要过滤出分数小于 80 分的学生,代码如下 :

//过滤出 studentList 中分数小于 80 分的 Student 对象
studentList.filter{
      it.score < 80 } 

输出如下:

[Student (id=3 ,name='Alice', age=16, score=70)]

另外,如果想要通过访问下标来过滤,可以使用 filterlndexed()函数

val list= listOf(l, 2, 3, 4, 5, 6, 7)
list.filterindexed {
      index, it -> index % 2 == 0 && it > 3 }

filterlndexed()函数签名如下 :

public inline fun <T> Iterable<T>.filterindexed(predicate: (index: Int, T)-> Boolean) : List<T>

7.7 排序函数

Kotlin集合类中提供了倒序排列集合元素的函数 reversed(),代码示例如下:

val list = listOf(1, 2, 3, 4, 5, 6, 7)
val set= setOf(1,3,2)
list.reversed() //倒序函数,返回[7, 6, 5, 4, 3, 2, 1]
set.reversed() //倒序函数,返回[2, 3, 1]

这个 Iterable 的扩展函数 reversed()是直接调用的 java.util.Collections.reverse()方法。其 相关代码如下:

public fun <T> Iterable<T> . reversed() : List<T> {
     
	if (this is Collection && s工ze <= 1) return toList () 
	val list = toMutableList ()
	list.reverse() //调用Java中List类型的reverse()方法 return list
}
public fun <T> MutableList<T>.reverse() : Unit {
      
	java.util.Collections .reverse(this)
}

升序排序函数是 sorted(),实例代码如下:

>>> list.sorted()
(1, 2, 3, 4, 5, 6, 7]
>> set.sorted()
(1, 2, 3]

Kotlin 中的这个 sorted()函数也是直接调用 Java的 API来实现的,相关代码如下:

public fun <T : Comparable<T> Iterable<T> . sorted() : List<T> {
      
	if (this is Collection) {
     
		if (size <= 1) return this.toList()
		@Suppress (” UNCHECKED_CAST” )
		return(toTypedArray<Comparable<T> () as Array<T>) .apply {
     sort()} .asList()
	}
	return toMutableList() .apply {
      sort() }
}

其背后调用的是 Java.util.Arrays.sort()方法 :

public fun <T> Array<out T> . sort() : Unit {
     
	if (size> 1) java.util.Arrays.sort(this)//调用 Java 中 Arrays类型的 sort芳法
}

7.8 元素去重

如果我们想对一个 List列表进行元素去重,可以直接调用 distinct()函数:

val dupList = listOf(1, 1, 2, 2, 3, 3, 3)
dupList.distinct() //去重函数, 返回[1,2, 3]

Kotlin 的集合类中还提供了许多功能丰富的 API,可以参考 官方 API 文档

你可能感兴趣的:(Kotlin)