Kotlin的集合
集合类
Java类库有一套相当完整的容器集合类用来持有对象。跟Java一样,集合类存放的都是对象的引用,而非对象本身(我们经常说的集合指的是集合中对象的引用),Kotlin的集合类是在Java的集合类库基础上进行的优化,新引入了不可变集合类等扩展,相关类和API都在kotlin.collections包里。
Kotlin的集合根据本身可变性可以分为两种:可变集合类与不可变集合类。
常用的集合类主要有三种:
·List(列表):List中的元素以线性方式存储,可以存放重复对象,且列表中的元素是有序地排列。根据可变性分为只读不可变的List和可变MutableList(可写入、删除数据)。
·Set(集):存放的元素无序、不重复。根据可变性分为不可变Set和可变MutableSet(可写入、删除数据)。
·Map(映射):持有的对象是“键值对”形式,每一个对象都包含一对键值Key-Value对象。其中key是唯一的,key决定对象在映射中的存储位置(但key本身并不能决定对象的存储位置,它通过哈希算法产生一个被称做哈希值的整数值,这个哈希值对应value的存储位置)。Map与List、Set一样,Map也分为只读Map和可变 MutableMap(可写入、删除数据)。需要注意的是,Map没有继承于Collection接口。
从数据结构的角度来看,List中的下标类似键值对中的Key, 只不过Key是有序的Int类型,所以说List也可以说是一种特殊的Map数据结构。而Set也是Key为Int类型,但是Value值是不能重复的特殊Map。
集合类接口
Kotlin中集合类接口的结构层次如图所示:
各接口对应功能如下:
集合的创建
常用API:
· 可使用listOf()、setOf()、mapOf()函数创建不可变的List 容器、Set容器、Map容器。
· 可使用mutableListOf()、 mutableSetOf()、mutableMapOf()函数来创建可变的MutableList容器、MutableSet容器、MutableMap容器。
· 可使用emptyList<>()创建一个空的List对象,使用emptySet()创建一个空的只读Set,使用emptyMap<K,V>()创建一个空的Map。
· Map还有相关linkedHashMapOf()和haspMapOf()。常用的mapOf()和mutableMapOf()创建的对象性质类似Java的LinkedHashMap。
声明格式代码示例如下:
val list = listOf(1,2,3,4,5) //不可变List
val mutableList = mutableListOf("1","2","3") //可变MutableList
val set = setOf(1,2,3,4,5) //不可变Set
val mutableSet = mutableSetOf("1","2","3") //可变MutableSet
val map = mapOf(1 to "one",2 to "two",3 to "haha") //创建不可变Map
val mutableMap = mutableMapOf(1 to "one",2 to "two",3 to "haha") //创建可变MutableMap
要想创建没有元素的空List,使用listOf()即可。不过创建空变量时,变量的类型不能省略(泛型),需要在声明时显式声明:
val emptyList: List<Int> = listOf() //显式声明List中的元素类型为Int
val emptyLIst2 = emptyList<Int>()
val emptySet: Set<Int> = setOf() //显式声明Set中的元素类型为Int
val emptySet2 = emptySet<Int>()
val emptyMap: Map<String,String> = mapOf() //显式声明Map中的元素类型为String,String键值对
val emptyMap2 = emptyMap<String,String>()
可以得出只读集合(listOf、setOf 和 mapOf)与可变集合(mutableList、mutableSetOf和 mutableMapOf)对应的kotlin&java集合的关系表:
方法 | Java类型 |
listOf() | kotlin.collections.EmptyList |
setOf() | kotlin.collections.EmptySet |
mapOf() | kotlin.collections.EmptyMap |
listOf(element: T) | java.util.Collections$SingletonList |
setOf(element: T) | java.util.Collections$SingletonSet |
mapOf(pair: Pair<K, V>) | java.util.Collections$SingletonMap |
listOf(vararg elements: T) | java.util.Arrays$ArrayList |
setOf(vararg elements: T) | java.util.LinkedHashSet |
mapOf(vararg pairs: Pair<K, V>) | java.util.LinkedHashMap |
mutableList() | java.util.ArrayList |
mutableSetOf() | java.util.LinkedHashSet |
mutableMapOf() | java.util.LinkedHashMap |
元素遍历
List、Set类继承了Iterable接口,里面扩展了forEach函数来进行遍历元素操作;Map接口中也扩展了forEach函数来迭代遍历元素。示例如下:
fun main(args: Array<String>) {
var list: List<Int> = listOf(1,2,3)
list.forEach{
print(it) //打印123 ,set和map使用同理
}
}
如果我们想在迭代遍历元素的时候访问index下标,在List和Set中可以使用forEachIndexed函数。如下示例:
fun main(args: Array<String>) {
var list: List<String> = listOf("a","b","c")
list.forEachIndexed { index: Int, i: String -> //第1个参数是下标,第2个参数是list中元素类型
println(" list key is $index and value is $i")
}
}
对应看到的控制台输出为:
映射函数
即对集合中每一个元素应用给定的函数,并把结果收集到一个新集合。基本的映射函数是 map()。 它将给定的 lambda 函数应用于每个后续元素,并返回 lambda 结果列表。 结果的顺序与元素的原始顺序相同。如果还需要用到元素索引作为参数的转换,请使用 mapIndexed()(对比下上面的forEachIndexed(),有没有发现什么?)。示例如下:
fun main(args: Array<String>) {
val number = setOf(1, 2, 3)
println(number.map { it * 3 }) //对应输出 [3, 6, 9]
println(number.mapIndexed { keys, value -> value * keys }) //对应输出[0, 2, 6]
}
如果转换的结果在某些元素上产生空值,则可以通过调用 mapNotNull() 函数取代 map() 或 mapIndexedNotNull() 取代 mapIndexed() 来从结果集中过滤掉 null 值。示例如下:
fun main(args: Array<String>) {
val number = setOf(1, 2, 3, 4)
println(number.map { if (it == 3) null else it * 2})
println(number.mapNotNull { if (it == 3) null else it * 2})
println(number.mapIndexed { keys, value -> if (keys == 2) null else value * keys })
println(number.mapIndexedNotNull { keys, value -> if (keys == 2) null else value * keys })
}
对应的控制台结果为:
观察其源码,可以发现:
/**
* Returns a list containing the results of applying the given [transform] function
* to each element in the original collection.
*
* @sample samples.collections.Collections.Transformations.map
*/
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
/**
* Applies the given [transform] function to each element of the original collection
* and appends the results to the given [destination].
*/
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
for (item in this)
destination.add(transform(item))
return destination
}
这个过程,就是创建一个新的ArrayList集合,遍历原集合,将函数类型对象处理过的值添加到新ArrayList对象中,并返回新的ArrayList对象。
此外,映射转换时,有两个选择:转换键,使值保持不变,反之亦然。 要将指定转换应用于键,请使用 mapKeys();反过来,mapValues() 转换值。 这两个函数都使用将映射条目作为参数的转换,因此可以操作其键与值。示例如下:
fun main(args: Array<String>) {
val number= mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 4)
println(number.mapKeys { it.key })
println(number.mapValues { it.value + it.key.length })
}
对应控制台输出为:
此外kotlin还有一个flatten()函数,用法在理解上是跟map()相反的场景,使用场景较少,这里不做重复介绍了。
过滤函数
filter()是kotlin最常用的高阶函数之一,作用就是过滤。它可以对Collection集合、Map集合或数组元素进行过滤,Collection集合和数组返回的是一个List集合,Map集合返回的还是一个Map集合。
fun main(args: Array<String>) {
val numbers = listOf("one", "two", "three", "four")
val newNumbers = numbers.filter { it.length > 3 }
println(newNumbers)
val numbersMap = mapOf("key10" to 1, "key2" to 2, "key30" to 3, "key4" to 4)
val newMaps = numbersMap.filter { (key, value) -> key.endsWith("0") && value > 2}
println(newMaps)
}
对应的控制台输出为:
与上述的map()类似,filter也有filterIndexed()(返回索引和值)和filterNot()(过滤空对象):
fun main(args: Array<String>) {
val numbers = listOf("one", "two", "three", "four")
val newNumbersOne = numbers.filter { it.length <= 3 }
val newNumbersTwo = numbers.filterIndexed { index, s -> (index != 0) && (s.length < 5) }
val newNumbersThree = numbers.filterNot { it.length <= 3 }
println(newNumbersOne)
println(newNumbersTwo)
println(newNumbersThree)
}
对应输出结果为:
我为什么说这个使用场景较多呢,假设你现在有几个Bean对象,要拿Bean对象的某一个属性进行对比(不一定是比大小),然后获取对比后的数据,就可以用到fliter()(这个场景在实际开发过程中很常见)。例如如下示例:
data class Students (val id: Int,var name:String,var age:Int,var score:Int)
fun main(args: Array<String>) {
var studentList = listOf(
Students(1,"jack",18,88),
Students(2,"nick",19,86),
Students(3,"James",20,99)
)
val student = studentList.filter { it.age > 18 } //过滤出studentList中年龄大于18的
println(student)
}
对应控制台输出为:
排序函数
Kotlin集合类中提供了倒序排列集合元素的函数reversed(),具体使用与Java的reversed()一样。示例如下:
fun main(args: Array<String>) {
val list = listOf(1,2,3,4,5)
val set = setOf("abc","jkl","zvm")
list.reversed()
set.reversed()
println(list) //对应输出[1, 2, 3, 4, 5]
println(set) //对应输出[abc, jkl, zvm]
}
对应的升序排序函数是sorted(),使用方法也跟Java一样,不做赘述:
fun main(args: Array<String>) {
val list = listOf(9,2,4,6,1)
val set = setOf(5,3,6)
println(list.sorted()) //对应输出[1, 2, 4, 6, 9]
println(set.sorted()) //对应输出[3, 5, 6]
}
元素去重
distinct()函数,功能描述即去除集合内的重复性元素。list和set可以使用,map不行(这个可以猜到的吧)。示例如下:
fun main(args: Array<String>) {
val list = listOf(9,2,9,4,1,1,4,6,1)
val set = setOf(5,3,5,6,1,6)
println(list.distinct()) //对应输出[9, 2, 4, 1, 6]
println(set.distinct()) //对应输出[5, 3, 6, 1]
}
使用方式简单,这里不做赘述。
End,如有其他问题请留言。