Kotlin-数组,集合类以及序列

发布于:2025-05-27 ⋅ 阅读:(68) ⋅ 点赞:(0)

数组

Kotlin中,数组是Array类型的对象

创建数组

有两种创建方式:

  1. 官方预设工具函数,如arrayOf arrayOfNulls emptyArray

比如创建一个包含5个数字的数组,那么我们可以像这样:

 val arr = arrayOf(1,2,3,4,5)
  1. 使用Array构造函数
fun main() {
    val arr = Array(5) {"我是元素$it"}
    for (element  in arr) {
        println(element )
    }
}

在这里插入图片描述

打印每一个元素

通过遍历下标取到元素

fun main() {
    val arr = arrayOf(1,2,3,4,5)
    for (i in 0..arr.size-1){
        print(arr[i])
    }
}

直接遍历元素

fun main() {
    val arr = arrayOf(1,2,3,4,5)
    for (element in arr){
        print(element)
    }
}

如果还是希望按照数组的下标进行遍历,也可以:

fun main() {
    val arr = arrayOf(1,2,3,4,5)
    for (index in arr.indices){
        print(arr[index])
    }
}

如果想同时遍历下标和元素本身,也可以使用withIndex函数,它会生成一系列IndexedValue对象(支持解构)

fun main() {
    val arr = arrayOf(1,2,3,4,5)
    for ((index, element) in arr.withIndex()){
        println("元素:$element, 下标:$index")
    }
}

如果需要使用Lambda表达式快速处理里面的每一个元素,也可以使用高阶函数

fun main() {
    val arr = arrayOf(1,2,3,4,5)
    arr.forEach { println(it) }                 //只带元素
    arr.forEachIndexed { index, element ->      //同时带下标和元素
        println("元素:$element, 下标:$index")
    }
}

如果只想打印数组里的内容,快速查看

fun main() {
    val arr = arrayOf(1,2,3,4,5)
    
    //使用joinToString将数组中的元素转换为字符串,默认使用逗号隔开
    println(arr.joinToString())
    
    //自定义分隔符,前后缀
    println(arr.joinToString("-"))
    println(arr.joinToString("-", "->", "<-"))
    
    //限制数量
    println(arr.joinToString(limit = 3))
    println(arr.joinToString(limit = 3, truncated = "....."))
    
    //自定义每个元素转换为字符串的结果
    println(arr.joinToString {                                         
        (it * it).toString()
    })
}

在这里插入图片描述

集合类

虽然数组能很方便的存储数据,但是长度是固定的,无法扩展。我们需要更强大的集合类来实现更多的高级功能。在Kotlin中,默认提供了以下类型的集合:

  • List:有序集合
  • Set:不包含重复元素的集合
  • Map:键值对结构

List

fun main() {
    //使用mutableListOf创建一个可修改的List集合
    val list: MutableList<Int> = mutableListOf(1,2,3,4,5)
    list[0] = 11
    println(list)
}

在这里插入图片描述
遍历列表也是跟数组一样

fun main() {
    val list: MutableList<Int> = mutableListOf(1,2,3,4,5)
    for (element  in list) print(element)
    for (index in list.indices) print(list[index])
    for ((index, element) in list.withIndex()) println("元素:$element, 下标:$index")

    list.forEach(::println)
    list.forEachIndexed { index, element ->      //同时带下标和元素
        println("元素:$element, 下标:$index")
    }
}

List比数组多了减法运算

fun main() {
    val l1 = listOf("AAA", "BBB", "CCC")
    val l2 = listOf("CCC", "DDD", "EEE")
    println(l1 + l2)
    println(l1 - l2)
}

在这里插入图片描述

Set

不能通过下标访问里面的元素,可以用迭代器的方式

fun main() {
    val set = mutableSetOf("AAA", "BBB", "CCC")
    //elementAt是通过迭代器的遍历顺序取到对应位置的元素
    println(set.elementAt(2))
}

由于Set就像数学上的集合概念,还有很多数学集合之间的操作

fun main() {
    val set1 = mutableSetOf("AAA", "BBB", "CCC")
    val set2 = mutableSetOf("CCC", "DDD", "EEE")
    println(set1 union set2) //求并集,"+"也是这个效果
    println(set1 intersect set2) //求交集
    println(set1 subtract  set2) //求差集,"-"也是这个效果
}

在这里插入图片描述
需要注意的是,集合相关的操作也可以应用于List,但计算结果是Set

fun main() {
    val l1 = mutableListOf("AAA", "BBB", "CCC")
    val l2 = mutableListOf("CCC", "DDD", "EEE")
    val set1: Set<String> = l1 union l2
    val set2: Set<String> = l1 intersect l2
    val set3: Set<String> = l1 subtract  l2
    println(set1)
    println(set2)
    println(set3)
}

在这里插入图片描述

Map

Kotlin提供了中缀函数来定义键值对

    val pair: Pair<Int, String> = 114514 to "小明"

这样,我们就创建了一个映射关系,但这仅仅是单个映射,如果要多个就可以用Map

访问元素用的不是下标而是key,同时得到的结果是可空类型的

fun main() {
    val map: MutableMap<Int, String> = mutableMapOf(
        1001 to "刘",
        1002 to "关",
        1003 to "张",
    )

    val name: String? = map[1001]
}

可以直接获取到key和value的集合

fun main() {
    val map: MutableMap<Int, String> = mutableMapOf(
        1001 to "刘",
        1002 to "关",
        1003 to "张",
    )

    val keys:MutableSet<Int> = map.keys
    val values: MutableCollection<String> = map.values
    val valuesList: List<String> = map.values.toList()
    println(keys)
    println(values)
    println(valuesList)
}

在这里插入图片描述
遍历Map:

fun main() {
    val map: MutableMap<Int, String> = mutableMapOf(
        1001 to "路飞",
        1002 to "鸣人",
        1003 to "一护",
    )

    map.forEach { key, value -> print("$key -> $value ") }

    println()

    for ((k,v) in map) {print("$k -> $v ")}

    println()

    for (entry in map.entries) {
        println("$entry")
        println("${entry.key} -> ${entry.value}")
    }
}

在这里插入图片描述
当插入一个键值对时,如果存在相同的key会覆盖之前的值,可以通过返回值来获取被覆盖的结果
注意返回结果是可空类型

fun main() {
    val map: MutableMap<Int, String> = mutableMapOf(
        1001 to "路飞",
        1002 to "鸣人",
        1003 to "一护",
    )
    val old:String? = map.put(1001, "金木")
    val old2:String? = map.put(1004, "纳兹")
    println(old)
    println(old2)
}

在这里插入图片描述
通过key移除键值对

fun main() {
    val map: MutableMap<Int, String> = mutableMapOf(
        1001 to "路飞",
        1002 to "鸣人",
        1003 to "一护",
        1004 to "纳兹",
    )
    map.remove(1001)
    map -= 1002
    map -= listOf(1003, 1004) //批量移除
}

通过value移除键值对

fun main() {
    val map: MutableMap<Int, String> = mutableMapOf(
        1001 to "路飞",
        1002 to "鸣人",
        1003 to "一护",
        1004 to "纳兹",
    )
    map.values.remove( "路飞")
    println(map)
}

在这里插入图片描述

迭代器

迭代器是每个集合类、数组都可以生成的东西,就是用于对内容的遍历

fun main() {
    val map: MutableMap<Int, String> = mutableMapOf(
        1001 to "路飞",
        1002 to "鸣人",
        1003 to "一护",
        1004 to "纳兹",
    )
    val iterator = map.iterator()
    while (iterator.hasNext()) {
        println(iterator.next())
    }
}

在这里插入图片描述
迭代器的出现,使得我们无论使用哪一种集合,都可以使用同样的方式对元素进行遍历

fun <T> forEach(iterator: Iterator<T>) { //统一接收迭代器对象
    while (iterator.hasNext()) {
        print(iterator.next().toString()+" ")
    }
    println()
}

fun main() {
    forEach(listOf("a","b","c").iterator())
    forEach(arrayOf("a","b","c").iterator())
    forEach(setOf("a","b","c").iterator())
    forEach(mapOf(
                1 to "a",
                2 to "b",
                3 to "c").iterator())
}

在这里插入图片描述
注意,迭代器使用是一次性的

只要是重写了 operator fun iterator() 函数的类型,都可以使用for..in(重载的运算符)这样的语法去进行遍历

自己写一个迭代器实现:

class Test: Iterable<String> {
    override operator fun iterator(): Iterator<String> = TestIterator()

    class TestIterator: Iterator<String> {
        override fun hasNext(): Boolean = true

        override fun next(): String = "666"
    }
}

fun main() {
    val test = Test()
    for (e in test) println(e)
}

Range语法,其本身也是一个支持生成迭代器的类

fun main() {
    val range: IntRange = 1..10
    val iterator: Iterator<Int> = range.iterator()
    while (iterator.hasNext()) {
        println(iterator.next())
    }
}

在这里插入图片描述
在JVM环境下,Kotlin默认不支持在迭代时修改集合里面的内容,无论是插入还是删除,都会触发并发修改异常

fun main() {
    var list = mutableListOf("AAA", "BBB", "CCC")
    for (item in list) {
        list.add("DDD")
    }
}

Kotlin为所有的MutableCollection提供了一个特殊的用于生成MutableIterator的函数

fun main() {
    val list = mutableListOf("AAA", "BBB", "CCC")
    val iterator:MutableIterator<String> = list.iterator()
    while (iterator.hasNext()) {
        iterator.next()
        iterator.remove()
    }
    println(list)
}

在这里插入图片描述

常见操作

数组转换为集合类

fun main() {
    val arr = arrayOf("AAA", "BBB", "CCC")
    val list = arr.toList()
    val mutableList = arr.toMutableList()
    val set = arr.toSet()
}

映射操作

fun main() {
    val list = listOf("AAA", "BB", "CCCCCC")
    val lenList: List<Int> = list.map { it.length }
    println(lenList)
}

在这里插入图片描述

fun main() {
    val numberMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 4)
    val a: List<String> = numberMap.map { it.key + " - " + it.value }
    println(a)
}

在这里插入图片描述

也可以取出下标

fun main() {
    val list = listOf("AAA", "BB", "CCCCCC")
    val mapList: List<String> = list.mapIndexed() { index, value -> "$index: $value" }
    println(mapList)
}

在这里插入图片描述
对于Map,还可以单独对Key或是Value进行操作

fun main() {
    val numberMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 4)
    println(numberMap.mapKeys { it.key.uppercase(Locale.getDefault()) })
    println(numberMap.mapValues { it.value+it.key.length })
}

在这里插入图片描述

压缩操作

它可以将当前集合元素和另一个集合中具有相同下标的元素组合起来

fun main() {
    val list1 = listOf(1,2,3,4,5)
    val list2 = listOf("A","B","C","D","E")
    val pairs: List<Pair<Int, String>> = list1.zip(list2)
    println(pairs)
}

在这里插入图片描述

利用压缩操作我们可以快速把两个List集合合并成一个Map集合

fun main() {
    val list1 = listOf(1,2,3,4,5)
    val list2 = listOf("A","B","C","D","E")
    val map: MutableMap<Int, String> = mutableMapOf()
    map.putAll( list1.zip(list2))
    println(map)
}

在这里插入图片描述
还能解压

fun main() {
    val list: List<Pair<Int, String>> = listOf(1 to "A", 2 to "B", 3 to "C", 4 to "D", 5 to "E")
    val unzipList: Pair<List<Int>, List<String>> = list.unzip()
    println(unzipList)
    println(unzipList.first)
    println(unzipList.second)
}

在这里插入图片描述
有些时候我们还可以使用另一种方式将普通集合转换为Map映射,比如associate操作

fun main() {
    val list: List<String> = listOf("AAA", "BBBB", "CC")
    val associate: Map<String, Int> = list.associateWith { it.length }
    println(associate)
}

在这里插入图片描述

fun main() {
    val list: List<String> = listOf("AAA", "BBBB", "CC")
    val associate: Map<Int, String> = list.associateBy { it.length }
    println(associate)
}

在这里插入图片描述
如果觉得以上两种方式不太灵活,也可以自行构建一个Pair作为结果返回

fun main() {
    val list: List<String> = listOf("AAA", "BBBB", "CC")
    val associate: Map<Int, String> = list.associate { it.length to it+it }
    println(associate)
}

在这里插入图片描述

扁平化操作

fun main() {
    val list = listOf(listOf(1,2), listOf(3,4), listOf(5,6), listOf(7,8))
    val flatten = list.flatten()
    println(flatten)
}

在这里插入图片描述

class A(val list:List<Int>)

fun main() {
    val list = listOf(A(listOf(1,2)), A(listOf(3,4)))
    val flatten = list.flatMap { it.list }
    println(flatten)
}

在这里插入图片描述

过滤

如果我们想要移除集合中某些不满足条件的元素,可以使用过滤操作来完成

fun main() {
    val list = listOf("AAA", "CC", "BBBB")
    val filter = list.filter { it.length > 2 }
    println(filter)
}

在这里插入图片描述

fun main() {
    val map = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 4)
    val filter = map.filter { (key, value) -> key == "key1" && value == 1 }
    println(filter)
}

在这里插入图片描述
快速过滤所有空值

fun main() {
    val list = listOf(1,2,null,3,null,4,5)
    val filter = list.filterNotNull()
    println(filter)
}

在这里插入图片描述
还可以快速过滤出指定类型的集合

fun main() {
    val list = listOf("AA", Any(), 12, 3.14, 0)
    val filter = list.filterIsInstance<Int>()
    println(filter)
}

在这里插入图片描述
如果我们既需要通过筛选的元素,也需要未通过筛选的元素,可以使用分区操作

fun main() {
    val list = listOf("AAAA","BB","CCC")
    val (match, mismatch) = list.partition { it.length >= 3 }
    println("匹配的列表: $match")
    println("不匹配的列表: $mismatch")
}

在这里插入图片描述

测试元素是否满足条件

fun main() {
    val list = listOf(1,2,3,4,5)
    println(list.any { it % 3 == 0 })  //判断集合中是否至少存在一个元素满足条件
    println(list.none { it > 0 })      //判断集合中是否不存在任何一个元素满足条件
    println(list.all { it > 0 })       //判断集合中是否每一个元素都满足条件
}

在这里插入图片描述

分组操作

fun main() {
    val list = listOf("11","22","3","444","555")
    val group: Map<Int, List<String>> = list.groupBy { it.length }
    println(group)
}

在这里插入图片描述

裁剪操作

fun main() {
    val list = listOf("AA", "BBB", "CC", "DDDD", "EEE")
    println(list.slice(1..3))          			 //截取第2个元素到第4个元素的切片
    println(list.take(2))                        //截取第一个元素开始长度为2的切片
    println(list.takeLast(2))                    //截取最后一个元素开始长度为2的切片
    println(list.drop(2))                        //跳过前2个元素进行截取
    println(list.dropLast(2))                    //跳过最后2个元素进行截取

    //从前往后截取符合条件的元素,遇到不符合的就返回
    println(list.takeWhile { it.length < 4 })
    //从后往前截取符合条件的元素,遇到不符合的就返回
    println(list.takeLastWhile { it.length > 2 })
}

在这里插入图片描述

序列

除了集合,Kotlin标准库还包含另一种类型:序列(Sequence)

与集合不同,序列不包含元素,它在运行时生成元素,接口定义如下,只包含一个生成迭代器的函数:
在这里插入图片描述
既然功能一样,为什么要专门搞一个序列呢?序列实际上是一个延迟获取数据的集合,只有需要元素时才会产生元素并提供给外部,包括所有对元素的操作也不是一次性全部处理,而是根据情况选择合适的元素进行操作,使用序列能够在处理大量数据时获得显著的性能提升

创建序列使用generateSequence函数即可

fun main() {
    val sequence: Sequence<Int> = generateSequence {
        println("生成一个新的元素")
        10 //返回值就是生成的元素
    }
}

这只是定义,运行也不会生成元素,只有真正使用的时候才会生成元素, 比如

fun main() {
    val sequence: Sequence<Int> = generateSequence {
        println("生成一个新的元素")
        10 //返回值就是生成的元素
    }
    sequence.forEach { print("$it ") }
}

可以比较一下同样是获取前两个长度大于2的字符串,并进行小写转换操作

fun main() {
    val list = listOf("AA","BBB","CCC","DD","EEE","FF","GGG")
    val result = list.filter {
        println("进行过滤操作: $it")
        it.length > 2
    }.map {
        println("进行小写转换操作: $it")
        it.lowercase()
    }.take(2)
    println(result)
}

在这里插入图片描述
可以发现,直接使用集合的情况下,整个工序是按照顺序向下执行的,并且每一道工序都会对所有的元素依次进行操作,但实际上根据我们的要求,最后只需要两个满足条件的元素即可,下面换成序列试试:

fun main() {
    val list = listOf("AA","BBB","CCC","DD","EEE","FF","GGG")
    val result = list.asSequence().filter {
        println("进行过滤操作: $it")
        it.length > 2
    }.map {
        println("进行小写转换操作: $it")
        it.lowercase()
    }.take(2)
    println(result.joinToString()) //如果没有这句,不获取元素,以上整个操作都是不会进行的
}

在这里插入图片描述
可以发现,序列根据我们的操作流程,对数据的操作也进行了优化,执行次数明显减少,并且只有我们从序列读取数据时才会执行定义好的工序

如果数据量特别庞大的情况下,使用序列会更好。如果数据量很小,使用序列反而会增加开销