当前位置: 首页 > news >正文

【Kotlin】数组集合常用扩展函数

在这里插入图片描述

大多数扩展对于数组和集合类都可以互相使用。这里大部分以 Array 为例。

更多详见 https://Kotlinlang.org/docs/collections-overview.html

数组与集合的转换

使用 Array 提供的集合快速转换函数转为集合

val array = arrayOf("AAA", "BBB", "CCC")
val list: List<String> = array.toList()
val list: MutableList<String> = array.toMutableList()
val set: Set<String> = array.toSet()
val set: MutableSet<String> = array.toMutableSet()

List、Set 转 Array

val list = listOf("Apple", "Banana", "Cherry")// 方式 1:使用 toTypedArray()
val array1 = list.toTypedArray()// 方式 2:使用 toArray()(较少用)
val array2 = list.toArray(arrayOfNulls<String>(list.size))println(array1.joinToString()) // 输出:Apple, Banana, Cherry
val set = setOf(1, 2, 3, 4)val array = set.toTypedArray()println(array.joinToString()) // 输出:1, 2, 3, 4

如果是数字类型,可以转成特定的原始数组:

val intList = listOf(1, 2, 3)
val intArray = intList.toIntArray()   // 输出类型:IntArrayprintln(intArray.joinToString())      // 输出:1, 2, 3

associateWith 将集合中的每个元素作为 key,通过指定的函数计算出对应的 value,最终生成一个 Map<K, V>

val words = listOf("apple", "banana", "cherry")
val map = words.associateWith { it.length }
println(map)    // {apple=5, banana=6, cherry=6}

associateByassociateWith 相反,它通过指定的函数计算出 key,而集合元素本身或通过另一个函数计算出的值作为 value

val words = listOf("apple", "banana", "cherry")
val map = words.associateBy { it.first() }
println(map)    // {a=apple, b=banana, c=cherry}val map = words.associateBy { it.length }
println(map)    // {5=apple, 6=cherry}     key 相同,被覆盖了

带 valueTransform

val map = words.associateBy(keySelector = { it.first() },valueTransform = { it.length }
)
println(map)    // {a=5, b=6, c=6}

associate是最通用的形式,允许你完全控制 key-value 对的生成规则

val words = listOf("apple", "banana", "cherry")
val map = words.associate { it.first() to it.length }
println(map)    // {a=5, b=6, c=6}

zip压缩,把两个集合按元素顺序配对,生成由 Pair 组成的List

val names = arrayOf("Alice", "Bob", "Charlie")
val ages = arrayOf(20, 25, 30)val result: List<Pair<String, Int>> = names.zip(ages)println(result)  // [(Alice, 20), (Bob, 25), (Charlie, 30)]// zip 把两个集合配成一个 List<Pair<K, V>> 再 .toMap() 把它转成 Map<K, V>
val map: Map<String, Int> = names.zip(ages).toMap()
println(map)  // {Alice=20, Bob=25, Charlie=30}val names = listOf("apple", "banana", "cherry")
val prices = listOf(1.5, 2.0, 3.2)
val fruitPriceMap = names.zip(prices).map { (name, price) -> name.uppercase() to "$${price}" }.toMap()
// 简化
// val fruitPriceMap = names.zip(prices).associate { (name, price) -> name.uppercase() to "$${price}" }
println(fruitPriceMap)  // {APPLE=$1.5, BANANA=$2.0, CHERRY=$3.2}

zip 还可以带一个 Lambda,用于直接合并生成新的类型

val names = arrayOf("Alice", "Bob", "Charlie")
val ages = arrayOf(20, 25, 30)// 返回值不是 Pair List 了
val result: List<String> = names.zip(ages) { name, age -> "$name is $age years old" }
println(result)   // [Alice is 20 years old, Bob is 25 years old, Charlie is 30 years old]

unzip,从Pair List拆分回 2 个 List

val list: List<Pair<Int, String>> = listOf(1 to "A", 2 to "B", 3 to "C")
val unzipList: Pair<List<Int>, List<String>> = list.unzip()  // 转换出来是一个存放两个List的Pair
println(unzipList)     // ([1, 2, 3], [A, B, C])val pairs = listOf("Alice" to 20,"Bob" to 25,"Charlie" to 30
)
val (names, ages) = pairs.unzip()
println(names)  // [Alice, Bob, Charlie]
println(ages)   // [20, 25, 30]

joinToString 打印内容

如果只是想打印数组里面的内容,可以使用 joinToString

val array: Array<Int> = arrayOf(7, 3, 9, 1, 6)
println(array.joinToString())  // 使用joinToString将数组中的元素转换为字符串,默认使用逗号隔开:7, 3, 9, 1, 6
println(array.joinToString(",", "[", "]"))  // 自定义分隔符,前后缀: [7,3,9,1,6]
println(array.joinToString(limit = 1, truncated = "..."))  // 甚至可以限制数量,多余的用自定义的字符串...代替: 7, ...
println(array.joinToString() { (it * it).toString() })   // 自定义每一个元素转换为字符串的结果

withIndex 与 IndexedValue 同时遍历索引和元素本身

同时遍历索引和元素本身,也可以使用 withIndex 函数,它会生成一系列 IndexedValue 对象。

使用 for in 遍历时,也可以对待遍历的元素进行【结构】操作,当然,前提是这些对象类型支持解构,比如 IndexedValue 就支持解构,所以可以在遍历时直接使用解构之后的变量进行操作:

val array: Array<Int> = arrayOf(7, 3, 9, 1, 6)
for ((index, item) in array.withIndex()) {  // 使用withIndex解构后可以同时遍历索引和元素println("元素$item,位置: $index")
}

forEach、forEachIndexed 遍历每一个元素,并对每个元素执行指定的操作(通过 lambda 表达式)

注意无返回值,映射是使用 map。

val array: Array<Int> = arrayOf(7, 3, 9, 1, 6)
array.forEach { println(it) }           // 只带元素
array.forEachIndexed { index, item ->   // 同时带索引和元素println("元素$item,位置: $index")
}

contentEquals、contentDeepEquals 比较数组内容是否相同

val array1: Array<Int> = arrayOf(1, 2, 3, 4, 5)
val array2: Array<Int> = arrayOf(1, 2, 3, 4, 5)
println(array1 == array2)   // false
println(array1 === array2)  // false
/* 
== 会调用 .equals() 方法。对于 数组 (Array) 来说,它并没有重写 equals,继承的是 Any.equals() 的实现。而 Any.equals() 默认是引用相等(也就是和 === 一样)。
*/
println(array1.contentEquals(array2))   // 需要使用扩展函数contentEquals来进行内容比较

对于多维数组,由于数组内存放的是数组,在比较两个嵌套数组的内容是否相同时,需要使用深度比较 contentDeepEquals

fun main() {val arr1: Array<IntArray> = arrayOf(intArrayOf(1, 2), intArrayOf(3, 4), intArrayOf(5, 6))val arr2: Array<IntArray> = arrayOf(intArrayOf(1, 2), intArrayOf(3, 4), intArrayOf(5, 6))println(arr1.contentEquals(arr2))            // falseprintln(arr1.contentDeepEquals(arr2))        // true
}/*
contentEquals只做浅比较,遇到子数组时比较引用
contentDeepEquals做深比较,递归比较子数组的内容
*/

copyOf 、copyOfRange 拷贝一个数组的内容并生成一个新的数组

val array1: Array<Int> = arrayOf(1, 2, 3, 4, 5)
val array2: Array<Int> = array1.copyOf()   // 使用copyOf来拷贝数据内容并创建一个新的数组存储println(array2 == array1)                // false
println(array2 === array1)               // false
println(array2.contentEquals(array1))    // true

可以指定拷贝的长度或是拷贝的范围

val array2: Array<Int?> = array1.copyOf(10)
// 在拷贝时指定要拷贝的长度,如果小于数组长度则只保留前面一部分内容,如果大于则在末尾填充null,因此返回的类型是Int?可空
val array2: Array<Int> = array1.copyOfRange(1, 3)  // 从第二个元素开始拷贝到第四个元素前为止,共2个元素
// 使用copyOfRange拷贝指定下标范围上的元素

sliceArray 分割数组

val array1 = arrayOf(1, 2, 3, 4, 5)
val array2 = array1.sliceArray(1..3)   // 从第二个元素到第四个元素共三个元素的数组

+拼接、-去重

val array1 = arrayOf(1, 2, 3, 4, 5)
val array2 = arrayOf(3, 7, 4, 9, 10)
val array3 = array1 + array2      // [1, 2, 3, 4, 5, 3, 7, 4, 9, 10]
val array4 = array3 + 11          // [1, 2, 3, 4, 5, 3, 7, 4, 9, 10, 11]

Array 没有 -

val l1 = listOf("AAA", "DDD", "CCC")
val l2 = listOf("BBB", "CCC", "EEE")
val l3 = l1 - l2  // 前面的集合减去与后面集合存在重复内容的部分: [AAA, DDD]val l4 = l1 + "H"
val l5 = l1 + l2

contains、in、indexOf、binarySearch 查找

val array = arrayOf(13, 16, 27, 32, 38)
println(array.contains(13))   // 判断数组中是否包含13这个元素
println(array in 13)   // 跟contains函数效果一样,判断数组中是否包含13这个元素
println(array.indexOf(26))    // 寻找指定元素的下标位置
println(array.binarySearch(16))    // 二分搜索某个元素的下标位置(效率吊打上面那个函数,但是需要数组元素有序)

注意,contains 如何判断对象相同

class Student(val name: String, val age: Int)fun main() {val array = arrayOf(Student("小明", 18), Student("小红", 17))println(array.contains(Student("小明", 18)))   // false
}

源码

public operator fun <@ Kotlin .internal.OnlyInputTypes T> Array<out T>.contains(element: T): Boolean {return indexOf(element) >= 0  // 调用内部indexOf函数看看能不能找到这个元素的下标
}public fun <@ Kotlin .internal.OnlyInputTypes T> Array<out T>.indexOf(element: T): Int {if (element == null) {...} else {for (index in indices) {   // 直接通过遍历的形式对数组内的元素一个一个进行判断if (element == this[index]) {   // 可以看到,这里判断使用的是==运算符return index}}}return -1
}

使用==的判断实际上取决于 equals 函数的重写,如果要让两个对象实现自定义的判断,需要重写对应类型的 equals 函数,否则无法实现自定义比较,默认情况下判断的是两个对象是否为同一个对象。重写 equals 再使用 contains 则为 true 了。

class Student(val name: String, val age: Int) {override fun equals(other: Any?): Boolean {if (this === other) return trueif (other !is Student) return falseif (name != other.name) return false  // 判断名字是否相同if (age != other.age) return false  // 判断年龄是否相同return true}
}

any 判断数组是否为空数组(容量为0)

println(array.any())   // 判断数组是否为空数组(容量为0)     非空为true

first、last 获取数组首尾元素

println(array.first())   // 快速获取首个元素
println(array.last())    // 快速获取最后一个元素

fill 填充

val array1 = arrayOf(1, 2, 3, 4, 5)
array1.fill(10)   // 重新将数组内部元素全部填充为10

reversedArray、reverse、shuffle、sort、sortDescending 排序

逆序

val array1: Array<Int> = arrayOf(1, 2, 3, 4, 5)
val array2: Array<Int> = array1.reversedArray()   // 翻转数组元素顺序,并生成新的数组
val array1: Array<Int> = arrayOf(1, 2, 3, 4, 5)
array1.reverse()   // 直接在原数组上进行元素顺序翻转
array1.reverse(1, 3)   // 仅翻转指定下标范围内的元素

打乱

array1.shuffle()  // 使用shuffle函数将数组中元素顺序打乱

排序

array1.sort()   // 使用sort函数对数组中元素进行排序,排序规则可以自定义
array1.sort(1, 3)   // 仅排序指定下标范围内的元素
array1.sortDescending()   // 按相反顺序排序

注意,排序操作并不是任何类型上来就支持的,由于这里使用的是基本类型 Int,它默认实现了 Comparable 接口,这个接口用于告诉程序排序规则,所以,如果数组中的元素是未实现 Comparable 接口的类型,那么无法支持排序操作。

// 首先类型需要实现Comparable接口,泛型参数T填写为当前类型
class Student(private val name: String, private val age: Int) : Comparable<Student> {// 接口中只有一个函数需要实现,这个是比较的核心算法,参数是另一个需要比较的元素,返回值Int类型// 使用当前对象this和给定对象other进行比较,如果返回小于0的数,说明当前对象应该排在前面,反之排后面,返回0表示同样的级别override fun compareTo(other: Student): Int = this.age - other.ageoverride fun toString(): String = "$name ($age)"
}

这样,自定义的类型就支持比较和排序了:

val array1 = arrayOf(Student("小明", 18), Student("小红", 17))
array1.sort()

sum 求和、average 求平均值、min、max 获取最值

val array: Array<Int> = arrayOf(1, 2, 3, 4, 5)
println(array.sum())            // 15
println(array.average())        // 3.0
println(array.min())            // 1
println(array.max())            // 5

map、mapIndexed 对数组中的每个元素进行转换(映射)

注意不会对原来的改变

val numbers = arrayOf(1, 2, 3, 4)
val squares = numbers.map { it * it }       // [1, 4, 9, 16]
val squaresIdx = numbers.mapIndexed { index, value ->  index * value}     // [0, 2, 6, 12]

filter、filterNotNull、filterIsInstance 过滤

val numbers = arrayOf(1, 2, 3, 4, 5, 6)
val evens = numbers.filter { it % 2 == 0 }   // [2, 4, 6]val numbers = arrayOf(1, 2, 3, 4, 5, 6)
val result = numbers.filter { it % 2 == 0 }  // 先筛选偶数.map { it * it }         // 再平方

Map 同样支持过滤

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10}
println(filteredMap) // {key11=11}

filterNotNull 过滤掉 null 元素,只保留非空的值。

val arr = arrayOf(1, null, 2, null, 3)
val result = arr.filterNotNull()      // 返回 List
println(result)    // [1, 2, 3]

filterIsInstance 过滤出指定类型的元素

val arr = arrayOf(1, "two", 3.0, "four")
val strings = arr.filterIsInstance<String>()
println(strings)  // [two, four]

flatten、flatMap 扁平化

对于多维(嵌套)

val arr: Array<Array<Int>> = arrayOf(arrayOf(1, 2, 3),arrayOf(4, 5),arrayOf(6)
)
val result = arr.flatten()      // 返回 List
println(result)    // [1, 2, 3, 4, 5, 6]

flatMap 先对集合中每个元素执行映射(返回集合),然后将结果“压平”成一个列表。

val list = listOf(Container(listOf("A", "B")), Container(listOf("C", "D")))
val flatList: List<String> = list.flatMap { it.list }   // 先将每一个Container映射为List
println(flatList)   // [AAA, BBB, CCC, DDD]
val arr = arrayOf(1, 2, 3)
val result = arr.flatMap { num ->arrayOf(num, num * 10).toList()
}
println(result)  // [1, 10, 2, 20, 3, 30]

chunked 分块、partition 分区、groupBy 分组

chunked(size: Int) 分成指定大小的块(最后一块可能更小) 【Array 没有此扩展】

val list = listOf(1, 2, 3, 4, 5, 6, 7)
val chunks: List<List<Int>> = list.chunked(3)
println(chunks)  // [[1, 2, 3], [4, 5, 6], [7]]

partition(predicate) 根据条件将集合分成两个部分:第一个包含符合条件的元素,第二个包含不符合条件的元素。返回 Pair<List, List>

val arr = arrayOf(1, 2, 3, 4, 5, 6)
val (even, odd) = arr.partition { it % 2 == 0 }
println("Even: $even")  // Even: [2, 4, 6]
println("Odd: $odd")    // Odd: [1, 3, 5]

groupBy(keySelector) 根据某个规则将元素分组,返回 Map<K, List<T>>。分组规则自定义,可以按长度、类型、首字母等。

val arr = arrayOf("apple", "banana", "avocado", "blueberry", "cherry")
val grouped = arr.groupBy { it.first() } // 按首字母分组
println(grouped)  // {a=[apple, avocado], b=[banana, blueberry], c=[cherry]}

any、none、all 判断条件是否满足

any 判断数组中是否 存在 至少一个元素满足条件,如果不传条件,则判断数组是否非空。

val arr = arrayOf(1, 2, 3, 4)
println(arr.any())           // true
println(arr.any { it > 3 })  // true
println(arr.any { it > 10 }) // false

none 判断数组中是否 没有 元素满足条件,如果不传条件,表示判断是否为空数组。

val arr = arrayOf(1, 2, 3)
println(arr.none())           // false
println(arr.none { it < 0 })  // true
println(arr.none { it == 2 }) // false

all 判断数组中 所有元素 是否都满足条件

val arr = arrayOf(2, 4, 6)
println(arr.all { it % 2 == 0 })  // true
println(arr.all { it < 6 })       // false

slice、take、drop 切片

slice(indices) 根据 索引范围索引列表 取出子集,返回 List

val arr = arrayOf("a", "b", "c", "d", "e")
println(arr.slice(1..3))      // [b, c, d]
println(arr.slice(listOf(0, 2, 4)))  // [a, c, e]

take(n) 取出数组开头的前 n 个元素,返回 List

val arr = arrayOf(10, 20, 30, 40, 50)
println(arr.take(3))     // [10, 20, 30]

takeLast(n) 取出数组末尾的 n 个元素,返回 List

val arr = arrayOf(10, 20, 30, 40, 50)
println(arr.take(2))     // [40, 50]

takeWhile 从头开始取元素,只要满足条件就继续取,直到遇到不满足的为止,返回 List

val arr = arrayOf(1, 2, 3, 2, 1)
println(arr.takeWhile { it < 3 })      // [1, 2]

drop(n) 跳过前 n 个元素,取剩下的,返回 List

val arr = arrayOf(10, 20, 30, 40, 50)
println(arr.drop(2))    // [30, 40, 50]

dropLast(n) 去掉最后 n 个元素,保留前面的,返回 List

val arr = arrayOf(10, 20, 30, 40, 50)
println(arr.dropLast(2))    // [10, 20, 30]
http://www.dtcms.com/a/532082.html

相关文章:

  • css新增盒子属性——尺寸调节
  • 做阿里国际网站会有成效吗上海网站建设公司招人
  • 【课堂笔记】概率论-3
  • 【硬件基础篇】:CPU如何被制造出来
  • 面向模块的综合技术之控制集优化(七)
  • 做网站广告软件网站系统设计目标
  • 使用稀疏采样方法减轻汽车雷达干扰——论文阅读
  • 阮一峰《TypeScript 教程》学习笔记——d.ts 类型声明文件
  • Spring AOP:横切关注点的优雅解决方案
  • 如何申请网站空间和注册域名鞋子软文推广300字
  • 基于AutoDL远端服务器在pycharm复现:具身智能论文pai0
  • 如何看访问网站的dns网站开发难不难
  • 数据结构·堆
  • 阮一峰《TypeScript 教程》学习笔记——类型映射
  • 需要做网站建设和推广网站地图插件
  • PyCharm 设置 Tabs and Indents
  • Spring Boot3零基础教程,生命周期监听,自定义监听器,笔记59
  • 【SpringBoot】详解Maven的操作与配置
  • 【C++】STL容器--priority_queue的使用与模拟实现
  • 【系统分析师】高分论文:论需求分析方法及应用(电子商务门户网站系统)
  • 【大模型应用开发 6.LangChain多任务应用开发】
  • 泰安最好的网站建设公司怎么通过做网站赚钱吗
  • 初识C语言15.文件操作
  • 聊聊连续、递增
  • 9款上班打卡软件测评:帮你选出最适合企业的工具
  • 建站服务网络公司建设宣传网站上的请示
  • Mem0 使用案例学习总结 - 记忆化应用结构
  • 如何自动清理 Linux 临时文件 ?
  • C++容器forward_list
  • 茂名网站建设培训品牌宣传网站