kotlin的集合操作
想要定义 kotlin 的集合比较简单, 你想要什么集合, 就给什么集合后面添加
Of
就出来了, setOf, hashSetOf, ArrayListOf, listOf, MapOf... 所以本文不讲如何创建集合了
集合转换
把旧集合通过某种方式转化成新的集合
map 映射
map 和 mapTo: 拿出一个个元素转化成新的
转化, 把 T
转化 成 R
, 然后再存入到一个新的集合中
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> { return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform) } 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 } 复制代码
destination: 是
ArrayList
类型 transform: 是转化函数
val list = (1..10).toMutableList() val map: List<Double> = list.map { it * 0.9 } println(map) // [0.9, 1.8, 2.7, 3.6, 4.5, 5.4, 6.3, 7.2, 8.1, 9.0] 复制代码
mapIndexed 带索引的映射
源码:
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapIndexedTo(destination: C, transform: (index: Int, T) -> R): C { var index = 0 for (item in this) // ****************** destination.add(transform(checkIndexOverflow(index++), item)) return destination } 复制代码
val indexed = list.mapIndexed { index, i -> "k: $index v: $i" } // [k: 0 v: 1, k: 1 v: 2, k: 2 v: 3, k: 3 v: 4, k: 4 v: 5, k: 5 v: 6, k: 6 v: 7, k: 7 v: 8, k: 8 v: 9, k: 9 v: 10] println(indexed) 复制代码
val notNullList: List<Byte> = list.mapNotNull { if (it % 2 == 0) { null } else { it.toByte() } } // [1, 3, 5, 7, 9] println(notNullList) 复制代码
zip 多个集合整合成一个
zip pair
源码:
public inline fun <T, R, V> Iterable<T>.zip(other: Iterable<R>, transform: (a: T, b: R) -> V): List<V> { val first = iterator() val second = other.iterator() val list = ArrayList<V>(minOf(collectionSizeOrDefault(10), other.collectionSizeOrDefault(10))) while (first.hasNext() && second.hasNext()) { // ****************** list.add(transform(first.next(), second.next())) } return list } 复制代码
根据方法简单的分析, 发现 T
发起的 zip合拢
操作, 将 R
类型的集合的数据, 借助 transform
函数, 将 T
和 R
传入 转化处新的类型 V
, 而返回的接口类型是 List<V>
是 ArrayList
类型
使用方法:
val colors = listOf("red", "brown", "grey") val animals = listOf("fox", "bear", "wolf") println(animals zip colors) // [(fox, red), (bear, brown), (wolf, grey)] val twoAnimal = listOf("fox", "bear") colors.zip(twoAnimal) // [(red, fox), (brown, bear)] 复制代码
上面这段代码走的是 zip(other) { t1, t2 -> t1 to t2 }
也就是说, 默认走的是 Pair
, 也就是说将 Pair
存入到 ArrayList
中
zip 自定义方法拦截映射
那么现在给个自定义方式的 zip
, public inline fun <T, R, V> Iterable<T>.zip(other: Iterable<R>, transform: (a: T, b: R) -> V): List<V>
使用方法:
val colors = listOf("red", "brown", "grey") val animals = listOf("fox", "bear", "wolf") println(colors.zip(animals) { color, animal -> "^$color, $animal^" }) 复制代码
unzip 解开 pair
unzip
函数: 解开 Pair
的 first
和 second
源码:
public fun <T, R> Iterable<Pair<T, R>>.unzip(): Pair<List<T>, List<R>> { val expectedSize = collectionSizeOrDefault(10) val listT = ArrayList<T>(expectedSize) val listR = ArrayList<R>(expectedSize) for (pair in this) { // ****************** listT.add(pair.first) listR.add(pair.second) } return listT to listR } 复制代码
使用方法:
val numberPairs = listOf("one" to 1, "two" to 2, "three" to 3, "four" to 4) val pair = numberPairs.unzip() println(pair.first) // [one, two, three, four] println(pair.second) // [1, 2, 3, 4] 复制代码
associate 关联: 把元素拆分成两个存放到新的集合中
associate
看起来就是把 T
按照某种方式分割成 k
和 v
然后存储到 Pair
中
使用方式:
val numbers = listOf("one", "two", "three", "four") val associate = numbers.associate { Pair(it.length, it) } println(associate) // {3=two, 5=three, 4=four} 复制代码
associateTo(LinkedHashMap<K, V>(capacity), transform)
他的返回值为 LinkedHashMap
源码:
public inline fun <T, K, V, M : MutableMap<in K, in V>> Iterable<T>.associateTo(destination: M, transform: (T) -> Pair<K, V>): M { for (element in this) { // ****************** destination += transform(element) } return destination } 复制代码
看其源码果然这样
不过值得注意的是 associateTo
associateTo: 提供集合和自定义拆解方法
val numbers = listOf("one", "two", "three", "four") val hashMap = numbers.associateTo(HashMap(10)) { Pair(it.length, it) } println(hashMap) // {3=two, 5=three, 4=four} 复制代码
associateBy: 借助集合元素获得 Key
val numbers = listOf("one", "two", "three", "four") val associateBy = numbers.associateBy { it.length } println(associateBy) // {3=two, 5=three, 4=four} 复制代码
源码:
public inline fun <T, K, M : MutableMap<in K, in T>> Iterable<T>.associateByTo(destination: M, keySelector: (T) -> K): M { for (element in this) { // ****************** destination.put(keySelector(element), element) } return destination } 复制代码
associateWith: 根据集合元素的值计算出 value
val numbers = listOf("one", "two", "three", "four") val associateWith = numbers.associateWith { it.length } println(associateWith) // {one=3, two=3, three=5, four=4} 复制代码
源码:
public inline fun <K, V, M : MutableMap<in K, in V>> Iterable<K>.associateWithTo(destination: M, valueSelector: (K) -> V): M { for (element in this) { // ****************** destination.put(element, valueSelector(element)) } return destination } 复制代码
associateBy: 自定义 key 和 自定义 value 方式
val numbers = listOf("one", "two", "three", "four") println(numbers.associateBy({ it.length }, { it.toUpperCase() })) // {3=TWO, 5=THREE, 4=FOUR} 复制代码
源码:
public inline fun <T, K, V> Iterable<T>.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V): Map<K, V> { val capacity = mapCapacity(collectionSizeOrDefault(10)).coerceAtLeast(16) return associateByTo(LinkedHashMap<K, V>(capacity), keySelector, valueTransform) } public inline fun <T, K, V, M : MutableMap<in K, in V>> Iterable<T>.associateByTo(destination: M, keySelector: (T) -> K, valueTransform: (T) -> V): M { for (element in this) { // 关键代码: destination.put(keySelector(element), valueTransform(element)) } return destination } 复制代码
flatten: 将集合的子集合全部拿出来创建成新的集合
List<List<String>>
val numberSets = listOf(setOf(1, 2, 3), setOf(4, 5, 6), setOf(1, 2)) val flatten = numberSets.flatten() println(flatten) // [1, 2, 3, 4, 5, 6, 1, 2] 复制代码
源码:
public fun <T> Iterable<Iterable<T>>.flatten(): List<T> { val result = ArrayList<T>() for (element in this) { result.addAll(element) } return result } 复制代码
flatMap: 将子List拿出来addAll到一个新的集合中
val containers = listOf( listOf("one", "two", "three"), listOf("four", "five", "six"), listOf("seven", "eight") ) val flatMap = containers.flatMap { it } println(flatMap) // [one, two, three, four, five, six, seven, eight] 复制代码
源码:
public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> { return flatMapTo(ArrayList<R>(), transform) } public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C { for (element in this) { val list = transform(element) destination.addAll(list) } return destination } 复制代码
其他的函数就不演示了, 和上面的 Map 和 associate 差不多
joinToString: 字符串打印方式自定义
val numbers = listOf("one", "two", "three", "four") val joinToString = numbers.joinToString(separator = "^", prefix = "#", postfix = "#", transform = { it.toUpperCase() }) println(joinToString) // #ONE^TWO^THREE^FOUR# 复制代码
源码:
public fun <T> Iterable<T>.joinToString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String { return joinTo(StringBuilder(), separator, prefix, postfix, limit, truncated, transform).toString() } public fun <T, A : Appendable> Iterable<T>.joinTo(buffer: A, separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): A { // buffer ==> StringBuilder buffer.append(prefix) var count = 0 for (element in this) { if (++count > 1) buffer.append(separator) if (limit < 0 || count <= limit) { buffer.appendElement(element, transform) } else break } // 如果 count 大于 limit 的话, 直接加入阶段字符串 if (limit >= 0 && count > limit) buffer.append(truncated) // 加入结尾标志 buffer.append(postfix) return buffer } 复制代码
过滤
根据接受的lambda返回的 true or false 来产生新的集合
filter: 分析每个元素是否满足某种条件
从遍历元素, 然后判断元素是否满足某种条件返回 boolean 类型
val numbers = listOf("one", "two", "three", "four") println(numbers.filter { it.length > 3 }) // [three, four] 复制代码
过滤 map 的条件是否满足
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11) println(numbersMap.filter { (key, value) -> key.endsWith("1") && value > 3 }) // {key11=11} 复制代码
filterIsInstance: 根据类型过滤
val numbers = listOf(1, "two", 3.0, "four") val list = numbers.filterIsInstance<Double>() println(list) 复制代码
源码:
partition: 根据某种条件分割一个集合为多个集合
val numbers = listOf("one", "two", "three", "four") val partition = numbers.partition { it.length > 3 } println(partition.first) println(partition.second) 复制代码
源码:
public inline fun <T> Iterable<T>.partition(predicate: (T) -> Boolean): Pair<List<T>, List<T>> { val first = ArrayList<T>() val second = ArrayList<T>() for (element in this) { // 核心代码在这里 if (predicate(element)) { first.add(element) } else { second.add(element) } } return Pair(first, second) } 复制代码
any all none 验证集合是否满足某个条件
val numbers = listOf("one", "two", "three", "four") println(numbers.any { it.startsWith("t") }) // true 只要有一个元素满足条件就返回true println(numbers.none { it.length < 2 }) // 如果有一个条件满足就返回 false , 否则返回 true println(numbers.all { it.length == 3 }) // 所有都要满足条件才会返回 true, 否则返回false 复制代码
groupby 分组
可以根据集合中的元素计算出分组的key
, 然后存放满足该key
的 List
val numbers = listOf("one", "two", "three", "four", "five") val groupBy = numbers.groupBy { it.length }.toSortedMap { o1, o2 -> o1 - o2 } println(groupBy) // {3=[one, two], 4=[four, five], 5=[three]} val groupBy1 = numbers.groupBy({ it.length }) { it.toUpperCase() } println(groupBy1) // {3=[ONE, TWO], 5=[THREE], 4=[FOUR, FIVE]} 复制代码
grouping: 根据 value 获得 key
val numbers = listOf("one", "two", "three", "four", "five", "six") val grouping = numbers.groupingBy { it.length } println(grouping.keyOf("six")) // 3 println(grouping.keyOf("three")) // 5 复制代码
取集合的⼀部分
Slice: 取一部分集合的元素(索引从0开始)
val numbers = listOf("one", "two", "three", "four", "five", "six") val slice = numbers.slice(0..3) // [one, two, three, four] println(slice) val slice1 = numbers.slice(3..5) // [four, five, six] println(slice1) 复制代码
take: 从头开始取前n个元素
val numbers = listOf("one", "two", "three", "four", "five", "six") println(numbers.take(1)) // [one] println(numbers.take(2)) // [one, two] println(numbers.take(6)) // [one, two, three, four, five, six] 复制代码
drop: 从头开始删除前n个元素
val numbers = listOf("one", "two", "three", "four", "five", "six") println(numbers.drop(1)) // 从前面开始删除前1个 println(numbers.drop(2)) // 从前面开始删除前2个 复制代码
Chunked: 分块
/* [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13]] [3, 12, 21, 30, 25] */ val numbers = (0..13).toList() val chunked: List<List<Int>> = numbers.chunked(3) println(chunked) // [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13]] val chunked1 = numbers.chunked(3) { list -> list.sum() } println(chunked1) // [3, 12, 21, 30, 25] 复制代码
Windowed: 步长自定义的分块函数
val numbers = listOf("one", "two", "three", "four", "five") val windowed = numbers.windowed(3, step = 1, partialWindows = false) { list -> list.map { it.toUpperCase() } } println(windowed) // [[ONE, TWO, THREE], [TWO, THREE, FOUR], [THREE, FOUR, FIVE]] 复制代码
subList: 从集合里找一个子集返回
val numbers = listOf("one", "two", "three", "four", "five", "six") println(numbers.javaClass) // class java.util.Arrays$ArrayList val subList = numbers.subList(0, 2) println(subList.javaClass) // class java.util.AbstractList$RandomAccessSubList println(subList) // [one, two] 复制代码
取单个元素
elementAt: 按位置取
val numbers = linkedSetOf("one", "two", "three", "four", "five") println(numbers.elementAt(0)) // one println(numbers.elementAt(3)) // four 复制代码
first 和 last
val numbers = linkedSetOf("one", "two", "three", "four", "five") println(numbers.first()) // one println(numbers.last()) // five 复制代码
first and last: 按条件取一个
val numbers = linkedSetOf("one", "two", "three", "four", "five") println(numbers.first { it.length == 4 }) // four 复制代码
find: 根据条件取一个
val numbers = listOf(1, 2, 3, 4) println(numbers.find { it > 3 }) // 4 复制代码
random: 随机取一个
val number = listOf(1, 2, 3, 4) println(number.random()) // 2 复制代码
检测存在与否
val numbers = listOf(1, 2, 3, 4) println(numbers.contains(2)) println(numbers.containsAll(listOf(3, 4))) 复制代码
还有
isEmpty
和isNotEmpty
就不做测试了
集合排序
Comparable
主要给类实现用
class Program(val version: Int) : Comparable<Int> { override fun compareTo(other: Int): Int = this.version - other } fun main() { val program = Program(13) println(program > 10) println(program > 13) println(program < 20) } 复制代码
还可以不使用Comparable
class Program(val version: Int) { operator fun compareTo(program2: Program): Int { return this.version - program2.version } operator fun compareTo(i: Int): Int { return this.version - i } } fun main() { val program1 = Program(13) val program2 = Program(14) println(program1 > program2) program1 > 14 } 复制代码
倒序和随机顺序
val numbers = listOf("one", "two", "three", "four") println(numbers) // [one, two, three, four] println(numbers.reversed()) // [four, three, two, one] println(numbers.asReversed()) // [four, three, two, one] println(numbers.shuffled()) // [four, one, three, two] 复制代码
集合聚合操作
val numbers = listOf(6, 42, 10, 4) println("Count: ${numbers.count()}") // Count: 4 println("Max: ${numbers.maxOrNull()}") // Max: 42 println("Min: ${numbers.minOrNull()}") // Min: 4 println("Average: ${numbers.average()}") // Average: 15.5 println("Sum: ${numbers.sum()}") // Sum: 62 复制代码
fold: 有初始化值R和集合T的某种组合的结果R返回回去
reduce: 把集合的第一个值当作S, 然后和集合的每个元素T做某种操作最后返回 S
set相关操作
联合 union 和 交集 intersect
val numbers = setOf("one", "two", "three") // 合并两个集合 println(numbers union setOf("four", "five")) // 找交集 println(numbers intersect setOf("one"))
作者:bangiao
链接:https://juejin.cn/post/7023015148382568461