赞
踩
今天介绍下 Kotlin
集合中的操作符,本文中 Kotlin
所用版本是 1.8.10
大部分的操作符是使用内联实现的,如果对内联函数感兴趣,可以康康我的这篇文章,Kotlin inline内联函数
all
判断集合中的所有元素是否满足需求,返回值为 Boolean
例如我们需要判断字符串的长度是否大于4
val songs = listOf("一路向北", "搁浅", "最长的电影")
songs.all { it.length >= 4 } // false
源码实现
// 继承Collection并且为空集合,直接返回为true
// 假如有一个元素不满足条件,直接返回false
public inline fun <T> Iterable<T>.all(predicate: (T) -> Boolean): Boolean {
if (this is Collection && isEmpty()) return true
for (element in this) if (!predicate(element)) return false
return true
}
any
判断集合中是否存在满足条件的元素,返回值为 Boolean
例如我们需要判断是否存在185cm 8块腹肌以上的小哥哥
val heights = listOf(188, 165, 175)
heights.any { it >= 185 } // true
源码实现
// 继承Collection并且为空集合,直接返回为false
// 假如有一个元素满足条件,直接返回true
public inline fun <T> Iterable<T>.any(predicate: (T) -> Boolean): Boolean {
if (this is Collection && isEmpty()) return false
for (element in this) if (predicate(element)) return true
return false
}
// 集合不是空就返回true了
public fun <T> Iterable<T>.any(): Boolean {
if (this is Collection) return !isEmpty()
return iterator().hasNext()
}
contains
集合是否包含某个元素,返回为 Boolean
例如判断班上是否有个名叫蔡徐坤的童鞋
val nickname = listOf("蔡徐坤", "坤蔡徐", "蔡坤徐", "蔡徐坤")
println(nickname.contains("蔡徐坤")) // true
源码实现
// 继承Collection,则通过Collection.contains()判断是否包含
// 负责通过indexOf判断
public operator fun <@kotlin.internal.OnlyInputTypes T> Iterable<T>.contains(element: T): Boolean {
if (this is Collection)
return contains(element)
return indexOf(element) >= 0
}
count
返回集合中的长度
val nickname = listOf("蔡徐坤", "坤蔡徐", "蔡坤徐", "蔡徐坤")
println(nickname.count()) // 4
源码实现
// 继承Collection,返回size
// 使用for循环计数
public fun <T> Iterable<T>.count(): Int {
if (this is Collection) return size
var count = 0
for (element in this) checkCountOverflow(++count)
return count
}
根据条件返回集合中满足条件的所有元素长度
例如我们需要统计班上的童鞋身高达到 185cm 的人数
val height = listOf(188, 165, 175, 185)
println(height.count { it >= 185 } ) // 2
源码实现
// 集合并且长度为0,返回0
// 满足predicate,计数累加并返回
public inline fun <T> Iterable<T>.count(predicate: (T) -> Boolean): Int {
if (this is Collection && isEmpty()) return 0
var count = 0
for (element in this) if (predicate(element)) checkCountOverflow(++count)
return count
}
distinct
过滤掉集合中相同的元素,返回一个新集合,实际是通过 HashSet
保证元素不重复
例如过滤掉重名的同学
val nickname = listOf("蔡徐坤", "坤蔡徐", "蔡坤徐", "蔡徐坤")
nickname.distinct() // [蔡徐坤, 坤蔡徐, 蔡坤徐]
源码实现
public fun <T> Iterable<T>.distinct(): List<T> {
return this.toMutableSet().toList()
}
distinctBy
根据条件过滤掉集合中的元素,返回一个新集合,实际是通过 HashSet
保证元素不重复
例如根据名字长度过滤
val nickname = listOf("蔡徐坤", "蔡", "坤蔡徐", "蔡坤徐", "蔡徐")
nickname.distinctBy { it.length } // [蔡徐坤, 蔡, 蔡徐]
如果想实现 distinct
过滤相同的元素,这样写即可(那还不如直接用 distinct
呢)
nickname.distinctBy { it }
源码实现
// HashSet可以添加元素,就将元素添加到list
public inline fun <T, K> Iterable<T>.distinctBy(selector: (T) -> K): List<T> {
val set = HashSet<K>()
val list = ArrayList<T>()
for (e in this) {
val key = selector(e)
if (set.add(key))
list.add(e)
}
return list
}
drop
过滤集合中前 n
个 元素,返回新的集合。n < 0
时抛出 IllegalArgumentException
异常,n = 0
时返回原集合,n >= 集合长度
时返回空集合
val heroName = listOf("蛮三刀", "托儿索", "儿童劫", "提款姬", "菊花信")
println(heroName.drop(0)) // [蛮三刀, 托儿索, 儿童劫, 提款姬, 菊花信]
println(heroName.drop(2)) // [儿童劫, 提款姬, 菊花信]
println(heroName.drop(6)) // []
源码实现
// n = 0,返回toList() // 继承Collection时,获取去除后的集合长度,长度为0返回emptyList,长度为1返回最后一个元素,否则通过ArrayList添加元素 public fun <T> Iterable<T>.drop(n: Int): List<T> { require(n >= 0) { "Requested element count $n is less than zero." } if (n == 0) return toList() val list: ArrayList<T> if (this is Collection<*>) { val resultSize = size - n if (resultSize <= 0) return emptyList() if (resultSize == 1) return listOf(last()) list = ArrayList<T>(resultSize) if (this is List<T>) { if (this is RandomAccess) { for (index in n until size) list.add(this[index]) } else { for (item in listIterator(n)) list.add(item) } return list } } else { list = ArrayList<T>() } var count = 0 for (item in this) { if (count >= n) list.add(item) else ++count } return list.optimizeReadOnlyList() }
dropLast
与 drop
刚好相反,dropLast
是从尾部过滤。n < 0
时抛出 IllegalArgumentException
异常,n = 0
时返回原集合,n >= 集合长度
时返回空集合
val heroName = listOf("蛮三刀", "托儿索", "儿童劫", "提款姬", "菊花信")
println(heroName.dropLast(0)) // [蛮三刀, 托儿索, 儿童劫, 提款姬, 菊花信]
println(heroName.dropLast(2)) // [蛮三刀, 托儿索, 儿童劫]
println(heroName.dropLast(6)) // []
源码实现
// 通过take()获取结果,take后面再说
public fun <T> List<T>.dropLast(n: Int): List<T> {
require(n >= 0) { "Requested element count $n is less than zero." }
return take((size - n).coerceAtLeast(0))
}
dropLastWhile
根据条件从尾部开始过滤元素,直到某个元素不满足条件时返回
例如现在求职者太多了,公司需要秉承先来后到并且职位更适合高个子的原则,舍弃掉末尾的求职者
val heights = listOf(185, 158, 177, 190, 169, 170, 168)
println(heights.dropLastWhile { it <= 175 }) // [185, 158, 177, 190]
println(heights.dropLastWhile { it < 170 }) // [185, 158, 177, 190, 169, 170]
源码实现
// 通过迭代器从后到前迭代,直到不满足条件时通过take截取
public inline fun <T> List<T>.dropLastWhile(predicate: (T) -> Boolean): List<T> {
if (!isEmpty()) {
val iterator = listIterator(size)
while (iterator.hasPrevious()) {
if (!predicate(iterator.previous())) {
return take(iterator.nextIndex() + 1)
}
}
}
return emptyList()
}
dropWhile
根据条件从头部开始过滤元素,与 dropLastWhile
刚好相反,直到某个元素不满足条件时返回剩余集合
还是上面的例子,不过我们调整下筛选的规则,公司需要后来先到的原则并且男士(或女士)优先的原则,舍弃掉头部的求职者
val names = listOf("陈女士", "张先生", "王先生", "蔡女士", "李先生", "钟女士", "朱先生")
println(names.dropWhile { it.endsWith("女士") }) // [张先生, 王先生, 蔡女士, 李先生, 钟女士, 朱先生]
println(names.dropWhile { it.endsWith("先生") }) // [陈女士, 张先生, 王先生, 蔡女士, 李先生, 钟女士, 朱先生]
源码实现
// for循环遍历,如果某个元素不满足条件,就把这个元素添加到集合并且把yielding置为true,后续的元素全部添加到集合
public inline fun <T> Iterable<T>.dropWhile(predicate: (T) -> Boolean): List<T> {
var yielding = false
val list = ArrayList<T>()
for (item in this)
if (yielding)
list.add(item)
else if (!predicate(item)) {
list.add(item)
yielding = true
}
return list
}
elementAt
返回索引下的元素,当索引不在有效范围内[0, lastIndex] 抛出数组越界异常,可以使用 elementAtOrNull
或 elementAtOrElse
代替
val mobileGames = listOf("和平精英", "英雄联盟手游", "欢乐斗地主")
println(mobileGames.elementAt(1)) // 英雄联盟手游
println(mobileGames.elementAt(mobileGames.lastIndex + 1)) // java.lang.ArrayIndexOutOfBoundsException 异常
源码实现
// List通过get方法获取
// 否则通过elementAtOrElse
public fun <T> Iterable<T>.elementAt(index: Int): T {
if (this is List)
return get(index)
return elementAtOrElse(index) { throw IndexOutOfBoundsException("Collection doesn't contain element at index $index.") }
}
elementAtOrElse
返回索引下的元素,当索引不在有效范围内[0, lastIndex] 时返回默认值
val mobileGames = listOf("和平精英", "英雄联盟手游", "欢乐斗地主")
println(mobileGames.elementAtOrElse(1) { "未找到游戏" }) // 英雄联盟手游
println(mobileGames.elementAtOrElse(mobileGames.lastIndex + 1) { "未找到游戏" }) // 未找到游戏
源码实现
public fun <T> Iterable<T>.elementAtOrElse(index: Int, defaultValue: (Int) -> T): T {
if (this is List)
return this.getOrElse(index, defaultValue)
if (index < 0)
return defaultValue(index)
val iterator = iterator()
var count = 0
while (iterator.hasNext()) {
val element = iterator.next()
if (index == count++)
return element
}
return defaultValue(index)
}
elementAtOrNull
返回索引下的元素,当索引不在有效范围内[0, lastIndex] 时返回null
例如
val list = listOf(1, 2, 3, 4, 5)
list.elementAtOrNull(3) = 4
list.elementAtOrNull(5) = null
源码实现
public fun <T> Iterable<T>.elementAtOrNull(index: Int): T? {
if (this is List)
return this.getOrNull(index)
if (index < 0)
return null
val iterator = iterator()
var count = 0
while (iterator.hasNext()) {
val element = iterator.next()
if (index == count++)
return element
}
return null
}
filter
按条件过滤元素,返回满足条件的所有元素
例如
val names = listOf("司马懿", "诸葛亮", "吕布", "黄忠", "赵云", "凤雏庞统")
println(names.filter { it.length >= 3 })
源码实现
// 通过filterTo实现,filterTo后面再说
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
return filterTo(ArrayList<T>(), predicate)
}
filterIndexed
按条件过滤元素,与 filter
不同的是 filterIndexed
的函数类型的参数会多一个 int
类型的 index
索引
例如我们以单双划分集合
val names = listOf("司马懿", "诸葛亮", "吕布", "黄忠", "赵云", "凤雏庞统")
val even = names.filterIndexed { index, _ -> index % 2 == 0 } // [司马懿, 吕布, 赵云]
val odd = names.filterIndexed { index, _ -> index % 2 == 1 } // [诸葛亮, 黄忠, 凤雏庞统]
源码实现
// 通过filterIndexedTo实现,传进去的集合是ArrayList
public inline fun <T> Iterable<T>.filterIndexed(predicate: (index: Int, T) -> Boolean): List<T> {
return filterIndexedTo(ArrayList<T>(), predicate)
}
filterIndexedTo
按条件过滤元素,将过滤后的元素添加到集合中
val names = listOf("司马懿", "诸葛亮", "司马懿", "吕布", "黄忠", "赵云", "凤雏庞统")
val evenSet = hashSetOf<String>()
val oddSet = hashSetOf<String>()
val even = names.filterIndexedTo(evenSet) { index, _ -> index % 2 == 0 } // [司马懿, 凤雏庞统, 黄忠]
val odd = names.filterIndexedTo(oddSet) { index, _ -> index % 2 == 1 } // [吕布, 诸葛亮, 赵云]
源码实现
// 传进来的集合必须是MutableCollection,因为会通过这个集合去添加过滤后的元素,返回传进来的集合
// 通过forEachIndexed过滤满足条件的元素
public inline fun <T, C : MutableCollection<in T>> Iterable<T>.filterIndexedTo(destination: C, predicate: (index: Int, T) -> Boolean): C {
forEachIndexed { index, element ->
if (predicate(index, element)) destination.add(element)
}
return destination
}
filterIsInstance
过滤同类型的元素,返回新的集合
例如我们有如下集合,我们需要以 String
和 Int
划分
val typeValues = listOf("蔡徐坤", 88, "唱跳rap", "篮球", 177, 68)
println(typeValues.filterIsInstance<String>()) // [蔡徐坤, 唱跳rap, 篮球]
println(typeValues.filterIsInstance<Int>()) // [88, 177, 68]
源码实现
// 通过filterIsInstanceTo实现,参数是ArrayList
public inline fun <reified R> Iterable<*>.filterIsInstance(): List<@kotlin.internal.NoInfer R> {
return filterIsInstanceTo(ArrayList<R>())
}
filterIsInstanceTo
过滤同类型的元素,将过滤后的元素添加到集合中
val stringSet = hashSetOf<String>()
val intSets = hashSetOf<Int>()
val typeValues = listOf("蔡徐坤", 88, "唱跳rap", "篮球", 177, 68)
println(typeValues.filterIsInstanceTo(stringSet))
println(typeValues.filterIsInstanceTo(intSets))
源码实现
// 通过for循环遍历集合,将符合类型的元素添加到传进来的集合中
public inline fun <reified R, C : MutableCollection<in R>> Iterable<*>.filterIsInstanceTo(destination: C): C {
for (element in this) if (element is R) destination.add(element)
return destination
}
filterNot
按条件过滤元素,返回不满足条件的所有元素,刚好与 filter
相反
例如我们需要获取大学名字长度不等于4的大学
val universitySet =
setOf("厦门大学", "四川大学", "清华大学", "中山大学", "武汉理工大学", "华南理工大学", "中国传媒大学")
println(universitySet.filterNot { it.length == 4 }) // [武汉理工大学, 华南理工大学, 中国传媒大学]
源码实现
// 通过filterNotTo过滤
public inline fun <T> Iterable<T>.filterNot(predicate: (T) -> Boolean): List<T> {
return filterNotTo(ArrayList<T>(), predicate)
}
filterNotNull
过滤掉 null
的元素
val random = listOf<Any?>("蔡徐坤", 2.5f, "唱跳rap", null)
println(random.filterNotNull()) //[蔡徐坤, 2.5, 唱跳rap]
源码实现
// 通过filterNotNullTo过滤
public fun <T : Any> Iterable<T?>.filterNotNull(): List<T> {
return filterNotNullTo(ArrayList<T>())
}
filterNotNullTo
过滤掉 null
的元素,将剩余的元素添加到传进来的集合中
val random = listOf<Any?>("蔡徐坤", 2.5f, "唱跳rap", null)
val hashSet = hashSetOf<Any>()
println(random.filterNotNullTo(hashSet)) // [2.5, 唱跳rap, 蔡徐坤]
源码实现
// 如果元素为空,则添加到传进来的集合中
public fun <C : MutableCollection<in T>, T : Any> Iterable<T?>.filterNotNullTo(destination: C): C {
for (element in this) if (element != null) destination.add(element)
return destination
}
filterNotTo
按条件过滤元素,将不满足条件的元素添加到传进来的集合中
例如
val universitySet =
setOf("厦门大学", "四川大学", "清华大学", "中山大学", "武汉理工大学", "华南理工大学", "中国传媒大学")
val lenNot4Items = hashSetOf<String>()
println(universitySet.filterNotTo(lenNot4Items) { it.length == 4 }) // [武汉理工大学, 华南理工大学, 中国传媒大学]
源码实现
// 将不满足条件的元素添加到传进来的集合中
public inline fun <T, C : MutableCollection<in T>> Iterable<T>.filterNotTo(destination: C, predicate: (T) -> Boolean): C {
for (element in this) if (!predicate(element)) destination.add(element)
return destination
}
filterTo
按条件过滤元素,将满足条件的元素添加到传进来的集合中, 刚好与 filterNotTo
相反
例如
@Test
fun filterToExample() {
val universitySet =
setOf("厦门大学", "四川大学", "清华大学", "中山大学", "武汉理工大学", "华南理工大学", "中国传媒大学")
val len4Items = hashSetOf<String>()
println(universitySet.filterTo(len4Items) { it.length == 4 }) // [厦门大学, 四川大学, 中山大学, 清华大学]
}
源码实现
// for循环遍历,将满足条件的添加到集合
public inline fun <T, C : MutableCollection<in T>> Iterable<T>.filterTo(destination: C, predicate: (T) -> Boolean): C {
for (element in this) if (predicate(element)) destination.add(element)
return destination
}
find
按条件查找满足条件的第一个元素,如果找到就直接返回,找不到返回null
例如
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
println(company.find { it.startsWith("A") }) // Apple
println(company.find { it.endsWith("G") }) // null
源码实现
// 内部通过firstOrNull实现
public inline fun <T> Iterable<T>.find(predicate: (T) -> Boolean): T? {
return firstOrNull(predicate)
}
findLast
按条件查找满足条件的最后一个元素,如果找到就直接返回,找不到返回null,与 find
查找顺序相反
例如
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
println(company.findLast { it.startsWith("A") }) // Alibaba
println(company.findLast { it.endsWith("G") }) // null
源码实现
// 内部通过lastOrNull实现
public inline fun <T> List<T>.findLast(predicate: (T) -> Boolean): T? {
return lastOrNull(predicate)
}
first
返回第一个元素或者第一个满足条件的元素,如果找不到该元素就抛出 NoSuchElementException
异常,可以使用 firstOrNull
代替
例如
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
println(company.first()) // Google
println(company.first { it.startsWith("A") }) // Apple
println(company.first { it.endsWith("G") }) // java.util.NoSuchElementException: Collection contains no element matching the predicate.
源码实现
public fun <T> List<T>.first(): T { if (isEmpty()) throw NoSuchElementException("List is empty.") return this[0] } // List 返回首个元素 // 否则使用迭代器返回 public fun <T> Iterable<T>.first(): T { when (this) { is List -> return this.first() else -> { val iterator = iterator() if (!iterator.hasNext()) throw NoSuchElementException("Collection is empty.") return iterator.next() } } }
firstNotNullOf
返回第一个转换后的非空元素,如果没有就抛出 NoSuchElementException
异常
例如
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
val companyMap = hashMapOf("抖音" to "字节", "快手" to "快手集团", "企鹅" to "腾讯")
println(company.firstNotNullOf { it.length }) // 6
println(company.firstNotNullOf { companyMap[it] }) // java.util.NoSuchElementException: No element of the collection was transformed to a non-null value.
源码实现
// 将转换函数传递给firstNotNullOfOrNull,如果firstNotNullOfOrNull返回空则抛出异常
public inline fun <T, R : Any> Iterable<T>.firstNotNullOf(transform: (T) -> R?): R {
return firstNotNullOfOrNull(transform) ?: throw NoSuchElementException("No element of the collection was transformed to a non-null value.")
}
firstNotNullOfOrNull
返回第一个转换后的非空元素,如果没有就返回 null
例如
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
val companyMap = hashMapOf("抖音" to "字节", "快手" to "快手集团", "企鹅" to "腾讯")
println(company.firstNotNullOfOrNull { it.length }) // 6
println(company.firstNotNullOfOrNull { companyMap[it] }) // null
源码实现
// 获取转换之后的值,如果不是空就返回
public inline fun <T, R : Any> Iterable<T>.firstNotNullOfOrNull(transform: (T) -> R?): R? {
for (element in this) {
val result = transform(element)
if (result != null) {
return result
}
}
return null
}
firstOrNull
返回第一个元素或者第一个满足条件的元素,如果没有就返回 null
例如
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
println(company.firstOrNull()) // Google
println(company.firstOrNull { it.startsWith("A") }) // Apple
println(company.firstOrNull { it.endsWith("G") }) // null
源码实现
// 对list单独处理,其他都是通过迭代器处理 public fun <T> Iterable<T>.firstOrNull(): T? { when (this) { is List -> { if (isEmpty()) return null else return this[0] } else -> { val iterator = iterator() if (!iterator.hasNext()) return null return iterator.next() } } } // for循环遍历 public inline fun <T> Iterable<T>.firstOrNull(predicate: (T) -> Boolean): T? { for (element in this) if (predicate(element)) return element return null }
flatMap
将集合中的元素根据转换函数得到新的值,并且将所有值铺平到新的集合中。与 map
不同的是,flatMap
的转换函数需要返回一个新的集合,并且会将转换后的值都铺平到集合中,所以如果有嵌套的集合转换成单层的集合时请使用 flatMap
例如
val intList = listOf(1, 2, 3, 4, 5)
val nestList = listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6, 7))
println(intList.flatMap { listOf(it + it, it * it, it * it * it) }) // [2, 1, 1, 4, 4, 8, 6, 9, 27, 8, 16, 64, 10, 25, 125]
println(nestList.flatMap { item -> item.map { it * it } }) // [1, 4, 9, 16, 25, 36, 49]
源码实现
// flatMapTo到ArrayList
public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
return flatMapTo(ArrayList<R>(), transform)
}
flatMapIndexed
与 flatMap
一样,不过 lambda
中多了个 index
索引参数
例如
val intList = listOf(1, 2, 3, 4, 5)
println(intList.flatMapIndexed { index, it -> listOf(it + it, it * it, it * it * it) })
源码实现
// flatMapIndexedTo到ArrayList
public inline fun <T, R> Iterable<T>.flatMapIndexed(transform: (index: Int, T) -> Iterable<R>): List<R> {
return flatMapIndexedTo(ArrayList<R>(), transform)
}
flatMapIndexedTo
flatMapIndexed
最终实现的源码,将转换后的元素添加到传进来的集合中
例如
val intList = listOf(1, 2, 3, 4, 5)
val hashSet = hashSetOf<Int>()
println(intList.flatMapIndexedTo(hashSet) { index, it -> listOf(it + it, it * it, it * it * it) }) // [16, 64, 1, 2, 4, 6, 8, 9, 25, 10, 27, 125]
println(hashSet) // [16, 64, 1, 2, 4, 6, 8, 9, 25, 10, 27, 125]
源码实现
// 遍历整个集合,将转换函数获得的集合添加到传进来的集合中
// checkIndexOverflow是防止数组越界
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapIndexedTo(destination: C, transform: (index: Int, T) -> Iterable<R>): C {
var index = 0
for (element in this) {
val list = transform(checkIndexOverflow(index++), element)
destination.addAll(list)
}
return destination
}
flatMapTo
flatMap
最终实现的源码,将转换后的元素添加到传进来的集合中
val nestList = listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6, 7))
val destSet = hashSetOf<Int>()
println(nestList.flatMapTo(destSet) { item -> item.map { it * it } })
println(destSet)
源码实现
// 遍历整个集合,将转换函数获得的集合添加到传进来的集合中
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
}
fold
对每个元素进行操作,返回积累的总值。集合为空则返回初始值
例如需要计算1到5的总和或者平方和
val intList = listOf(1, 2, 3, 4, 5)
println(intList.fold(0) { prev, item -> prev + item }) // 15
println(intList.fold(0) { prev, item -> prev + item * item }) // 55
源码实现
// 遍历整个集合,将上一个的结果传到下一个的遍历中,需要传入初始值
public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) -> R): R {
var accumulator = initial
for (element in this) accumulator = operation(accumulator, element)
return accumulator
}
foldIndexed
与 fold
一样,只是 lambda
中多了个 index
索引参数
val intList = listOf(1, 2, 3, 4, 5)
println(intList.foldIndexed(0) { index, prev, item -> prev + item })
println(intList.foldIndexed(0) { index, prev, item -> prev + item * item })
源码实现
// 遍历整个集合,将上一个的结果传到下一个的遍历中,需要传入初始值
public inline fun <T, R> Iterable<T>.foldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): R {
var index = 0
var accumulator = initial
for (element in this) accumulator = operation(checkIndexOverflow(index++), accumulator, element)
return accumulator
}
foldRight
对每个元素进行操作,返回积累的总值。与 fold
不同的是,foldRight
是从右到左积累,fold
是从左到右积累。因为是有顺序的,所以只作用于 list
注意 这里的 lambda
表达式的第一个参数是元素,第二个参数是上一次操作的值
val intList = listOf(1, 2, 3, 4, 5)
println(intList.foldRight(0) { item, prev -> prev + item }) // 15
println(intList.foldRight(0) { item, prev -> prev + item * item }) // 55
源码实现
// 通过listIterator迭代整个list,如果为空返回默认值
public inline fun <T, R> *List*<T>.foldRight(initial: R, operation: (T, acc: R) -> R): R {
var accumulator = initial
if (!isEmpty()) {
val iterator = listIterator(size)
while (iterator.hasPrevious()) {
accumulator = operation(iterator.previous(), accumulator)
}
}
return accumulator
}
foldRightIndexed
与 foldRight
一样,只是 lambda
中多了个 index
索引参数
注意 这里的 lambda
表达式的第一个参数是索引,第二个参数是元素,第三个参数是上一次操作的值
val intList = listOf(1, 2, 3, 4, 5)
println(intList.foldRightIndexed(0) { index, item, prev -> prev + item }) // 15
println(intList.foldRightIndexed(0) { index, item, prev -> prev + item * item }) 35
源码实现
// // 通过listIterator迭代整个list,如果为空返回默认值
public inline fun <T, R> *List*<T>.foldRightIndexed(initial: R, operation: (index: Int, T, acc: R) -> R): R {
var accumulator = initial
if (!isEmpty()) {
val iterator = listIterator(size)
while (iterator.hasPrevious()) {
val index = iterator.previousIndex()
accumulator = operation(index, iterator.previous(), accumulator)
}
}
return accumulator
}
forEach
forEach
遍历,lambda
返回每一个元素
val intList = listOf(1, 2, 3, 4, 5)
intList.forEach {
println(it)
}
// 1 2 3 4 5
源码实现
// for循环遍历
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
for (element in this) action(element)
}
关于 forEach
如何退出,可以康康我的这篇文章 forEach 中 如何退出循环?
forEachIndexed
与 forEach
一样,只是 lambda
中多了个 index
索引参数
源码实现
// for循环遍历
public inline fun <T> Iterable<T>.forEachIndexed(action: (index: Int, T) -> Unit): Unit {
var index = 0
for (item in this) action(checkIndexOverflow(index++), item)
}
getOrElse
获取 List
中某个索引的值,如果 索引不在范围 [0, lastIndex] 内时,则返回默认值。只作用于List
有的时候我们需要获取某个索引的值又害怕出现数组越界,可以采用这个函数
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
println(company.getOrElse(8) { "unknown" }) // unknown
println(company.getOrElse(2) { "unknown" }) // IBM
println(company[8]) // java.lang.ArrayIndexOutOfBoundsException
源码实现
// 没有数组越界通过 get方法获取,数组越界返回默认值
public inline fun <T> List<T>.getOrElse(index: Int, defaultValue: (Int) -> T): T {
return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index)
}
getOrNull
获取 List
中某个索引的值,如果 索引不在范围 [0, lastIndex] 内时,则返回 null
,与 getOrElse
类似不过默认值是 null
。只作用于List
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
println(company.getOrNull(8)) // null
println(company.getOrNull(2)) // IBM
源码实现
// 没有数组越界通过 get方法获取,数组越界返回null
public fun <T> List<T>.getOrNull(index: Int): T? {
return if (index >= 0 && index <= lastIndex) get(index) else null
}
groupBy
根据分组函数对集合进行分组,返回分组结果 Map
,Map
中的 key
类型由分组函数决定, value
的类型是 List
groupBy
两个参数的函数会对集合元素的值进行转换,最终添加到 Map
中
例如我们需要对字符串按长度进行分组,那么 Map
中 key
就是 Int
类型
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
println(company.groupBy { it.length }) // {6=[Google], 9=[Microsoft], 3=[IBM], 5=[Apple, Yahoo, Baidu], 7=[Alibaba]}
// 两个参数,给元素添加个_下标
println(company.groupBy({ it.length }) { it + "_" }) // {6=[Google_], 9=[Microsoft_], 3=[IBM_], 5=[Apple_, Yahoo_, Baidu_], 7=[Alibaba_]}
源码实现
// 通过groupByTo实现,传入的是LinkedHashMap,所以返回的其实是LinkedHashMap对象
public inline fun <T, K> Iterable<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>> {
return groupByTo(LinkedHashMap<K, MutableList<T>>(), keySelector)
}
public inline fun <T, K, V> Iterable<T>.groupBy(keySelector: (T) -> K, valueTransform: (T) -> V): Map<K, List<V>> {
return groupByTo(LinkedHashMap<K, MutableList<V>>(), keySelector, valueTransform)
}
groupByTo
groupBy
最终的实现,将键值对添加到传进来的 MutableMap
中
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
val lenToStringMap = hashMapOf<Int, MutableList<String>>()
val lenToStringTransformMap = hashMapOf<Int, MutableList<String>>()
println(company.groupByTo(lenToStringMap) { it.length }) // {3=[IBM], 5=[Apple, Yahoo, Baidu], 6=[Google], 7=[Alibaba], 9=[Microsoft]}
println(company.groupByTo(lenToStringTransformMap, { it.length }) { it + "_" }) // {3=[IBM_], 5=[Apple_, Yahoo_, Baidu_], 6=[Google_], 7=[Alibaba_], 9=[Microsoft_]}
println(lenToStringMap) // {3=[IBM], 5=[Apple, Yahoo, Baidu], 6=[Google], 7=[Alibaba], 9=[Microsoft]}
println(lenToStringTransformMap) // {3=[IBM_], 5=[Apple_, Yahoo_, Baidu_], 6=[Google_], 7=[Alibaba_], 9=[Microsoft_]}
源码实现
// 根据分组函数获取Map的key值,通过MutableMap的getOrPut获取value,将元素添加到list中 public inline fun <T, K, M : MutableMap<in K, MutableList<T>>> Iterable<T>.groupByTo(destination: M, keySelector: (T) -> K): M { for (element in this) { val key = keySelector(element) val list = destination.getOrPut(key) { ArrayList<T>() } list.add(element) } return destination } // 在上面的基础上多了一步转换 public inline fun <T, K, V, M : MutableMap<in K, MutableList<V>>> Iterable<T>.groupByTo(destination: M, keySelector: (T) -> K, valueTransform: (T) -> V): M { for (element in this) { val key = keySelector(element) val list = destination.getOrPut(key) { ArrayList<V>() } list.add(valueTransform(element)) } return destination }
indexOf
获取元素的索引,当不存在该元素时返回 -1,如果只是判断是否在集合中 优先采用 contains
val kingdoms = setOf("秦", "楚", "齐", "燕", "赵", "魏", "韩")
println(kingdoms.indexOf("齐")) // 2
println(kingdoms.indexOf("唐")) // -1
源码实现
// for循环遍历整个集合,若在集合内则返回索引,否则返回-1
public fun <@kotlin.internal.OnlyInputTypes T> Iterable<T>.indexOf(element: T): Int {
if (this is List) return this.indexOf(element)
var index = 0
for (item in this) {
checkIndexOverflow(index)
if (element == item)
return index
index++
}
return -1
}
indexOfFirst
获取第一个满足条件的元素的索引,当所有元素都不满足条件时返回 -1
val typeValues = listOf("蔡徐坤", 88, "唱跳rap", "篮球", 177, 68)
println(typeValues.indexOfFirst { it == "唱跳rap" }) // 2
println(typeValues.indexOfFirst { it == "两年半" }) // -1
源码实现
// for循环遍历整个集合,若元素满足条件则返回该元素的索引,否则返回-1
public inline fun <T> List<T>.indexOfFirst(predicate: (T) -> Boolean): Int {
var index = 0
for (item in this) {
if (predicate(item))
return index
index++
}
return -1
}
indexOfLast
获取最后一个满足条件的元素的索引,当所有元素都不满足条件时返回 -1
val typeValues = listOf("蔡徐坤", 88, "唱跳rap", "篮球", 177, "唱跳rap", 68)
println(typeValues.indexOfLast { it == "唱跳rap" }) // 5
println(typeValues.indexOfLast { it == "两年半" }) // -1
源码实现
// for循环遍历整个集合,若某个元素满足条件则将lastIndex置为该索引,最终返回lastIndex
public inline fun <T> Iterable<T>.indexOfLast(predicate: (T) -> Boolean): Int {
var lastIndex = -1
var index = 0
for (item in this) {
checkIndexOverflow(index)
if (predicate(item))
lastIndex = index
index++
}
return lastIndex
}
intersect
获取两个集合中交集,返回的是 set
val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
val finalFourBy2022 = listOf("凯尔特人", "勇士", "热火", "独行侠")
println(finalFourBy2023.intersect(finalFourBy2022)) // [凯尔特人, 热火]
源码实现
// 通过retainAll获取交集
public infix fun <T> Iterable<T>.intersect(other: Iterable<T>): Set<T> {
val set = this.toMutableSet()
set.retainAll(other)
return set
}
joinTo
将所有的元素连接到一起,通过前缀、后缀和分隔符连接。一般我们都是使用 StringBuilder
进行格式化输出,用得更多的是 joinToString
val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
val sb = StringBuilder()
println(finalFourBy2023.joinTo(sb, separator = "#", prefix = "{", postfix = "}")) // {凯尔特人#热火#湖人#掘金}
源码实现
// 通过Appendable添加前缀、转换后的元素、分隔符和后缀
// StringBuilder 继承了Appendable
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.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
}
if (limit >= 0 && count > limit) buffer.append(truncated)
buffer.append(postfix)
return buffer
}
joinToStrin
格式化输出集合中的所有元素,返回字符串
val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
println(finalFourBy2023.joinToString(separator = "#", prefix = "{", postfix = "}")) // {凯尔特人#热火#湖人#掘金}
源码实现
// 通过joinTo实现,StringBuilder继承了Appendable
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()
}
last
获取最后一个元素或者最后一个满足条件的元素,如果找不到该元素就抛出 NoSuchElementException
异常,可以使用 lastOrNull
代替,与 first
刚好相反
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
println(company.last()) // Baidu
println(company.last { it.startsWith("A") }) // Alibaba
println(company.first { it.endsWith("G") }) // java.util.NoSuchElementException
源码实现
// 通过found去判断是否有满足条件的元素 // 满足条件给last赋值并最终返回last public inline fun <T> Iterable<T>.last(predicate: (T) -> Boolean): T { var last: T? = null var found = false for (element in this) { if (predicate(element)) { last = element found = true } } if (!found) throw NoSuchElementException("Collection contains no element matching the predicate.") @Suppress("UNCHECKED_CAST") return last as T } // 对List单独处理,返回List.last // 使用迭代器迭代,返回最后一个元素 public fun <T> Iterable<T>.last(): T { when (this) { is List -> return this.last() else -> { val iterator = iterator() if (!iterator.hasNext()) throw NoSuchElementException("Collection is empty.") var last = iterator.next() while (iterator.hasNext()) last = iterator.next() return last } } } // 获取索引lastIndex的元素 public fun <T> List<T>.last(): T { if (isEmpty()) throw NoSuchElementException("List is empty.") return this[lastIndex] }
lastIndexOf
获取某个元素在集合中最后一个元素的索引,当不存在该元素时返回-1。indexOf
是获取第一个出现该元素的索引 ,lastIndexOf
与 indexOf
刚好相反
val typeValues = listOf("蔡徐坤", 88, "唱跳rap", "篮球", 177, "唱跳rap", 68)
println(typeValues.lastIndexOf("唱跳rap")) // 5
println(typeValues.lastIndexOf("两年半")) // -1
源码实现
// 对list单独处理,返回List.lastIndexOf
// 否则for循环遍历集合,获取lastIndex
public fun <@kotlin.internal.OnlyInputTypes T> Iterable<T>.lastIndexOf(element: T): Int {
if (this is List) return this.lastIndexOf(element)
var lastIndex = -1
var index = 0
for (item in this) {
checkIndexOverflow(index)
if (element == item)
lastIndex = index
index++
}
return lastIndex
}
lastOrNull
获取最后一个元素或者最后一个满足条件的元素,如果找不到该元素则返回 null
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
println(company.lastOrNull()) // Baidu
println(company.lastOrNull { it.startsWith("A") }) // Alibaba
println(company.lastOrNull { it.endsWith("G") }) //null
源码实现
// for循环遍历集合,满足条件就给last赋值,最终返回last public inline fun <T> Iterable<T>.lastOrNull(predicate: (T) -> Boolean): T? { var last: T? = null for (element in this) { if (predicate(element)) { last = element } } return last } // 对list单独判断,如果是空返回null,否则返回最后一个元素 // 迭代器迭代集合,返回last public fun <T> Iterable<T>.lastOrNull(): T? { when (this) { is List -> return if (isEmpty()) null else this[size - 1] else -> { val iterator = iterator() if (!iterator.hasNext()) return null var last = iterator.next() while (iterator.hasNext()) last = iterator.next() return last } } }
map
根据转换函数进行转换元素,得到一个包含所有转换之后的元素的 List
val intList = listOf(1, 2, 3, 4, 5)
val nestList = listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6, 7))
println(intList.map { it * it }) // [1, 4, 9, 16, 25]
println(nestList.map { item -> item.map { it * it } }) // [[1, 4], [9, 16], [25, 36, 49]]
可以很明显看到 map
和 flatMap
的区别,flatMap
会铺平整个集合,而 map
只是将转换元素累计
源码实现
// 调用mapTo实现,传入转换函数和ArrayList
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
mapIndexed
与 map
一样,只是 lambda
中多了个 index
索引参数
val intList = listOf(1, 2, 3, 4, 5)
val nestList = listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6, 7))
println(intList.mapIndexed { index, i -> "$index: $i" }) // [0: 1, 1: 2, 2: 3, 3: 4, 4: 5]
println(nestList.mapIndexed { index, item ->
item.map {
when (index) {
nestList.lastIndex -> it * it * it
else -> it * it
}
}
}) // [[1, 4], [9, 16], [125, 216, 343]]
源码实现
// 调用mapIndexedTo实现,传入转换函数和ArrayList
public inline fun <T, R> Iterable<T>.mapIndexed(transform: (index: Int, T) -> R): List<R> {
return mapIndexedTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
mapIndexedNotNull
根据转换函数进行转换元素,得到一个包含所有转换之后的非空元素的 List
,与 mapIndexed
对比 mapIndexedNotNull
不包含 null
元素
val intList = listOf(1, 2, 3, 4, 5)
println(intList.mapIndexedNotNull { index, i ->
when (index) {
intList.lastIndex -> null
else -> i * i
}
}) // [1, 4, 9, 16]
// 由于最后一个元素我们转换为了 null,所以不输出
源码实现
// 通过mapIndexedNotNullTo
public inline fun <T, R : Any> Iterable<T>.mapIndexedNotNull(transform: (index: Int, T) -> R?): List<R> {
return mapIndexedNotNullTo(ArrayList<R>(), transform)
}
mapIndexedNotNullTo
mapIndexedNotNull
的终极实现,将转换后的非空元素添加到集合参数中
val intList = listOf(1, 2, 3, 4, 5)
val hashSet = hashSetOf<Int>()
println(intList.mapIndexedNotNullTo(hashSet) { index, i ->
when (index) {
intList.lastIndex -> null
else -> i * i
}
}) // [16, 1, 4, 9]
源码实现
// forEachIndexed遍历,然后对每个元素进行转换,?.是判断元素非空
public inline fun <T, R : Any, C : MutableCollection<in R>> Iterable<T>.mapIndexedNotNullTo(destination: C, transform: (index: Int, T) -> R?): C {
forEachIndexed { index, element -> transform(index, element)?.let { destination.add(it) } }
return destination
}
mapIndexedTo
mapIndexed
的终极实现,将转换后的元素添加到集合参数中
val intList = listOf(1, 2, 3, 4, 5)
val nestList = listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6, 7))
val stringSet = hashSetOf<String>()
val nestSet = linkedSetOf<List<Int>>()
println(intList.mapIndexedTo(stringSet) { index, i -> "$index: $i" }) // [3: 4, 4: 5, 1: 2, 2: 3, 0: 1]
println(nestList.mapIndexedTo(nestSet) { index, item ->
item.map {
when (index) {
nestList.lastIndex -> it * it * it
else -> it * it
}
}
}) // [[1, 4], [9, 16], [125, 216, 343]]
源码实现
// for循环遍历,转换后添加到集合参数中
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
}
mapNotNull
根据转换函数进行转换元素,得到一个包含所有转换之后的非空元素的 List
。与map
不同的是,mapNotNull
不会出现 null
val intList = listOf(1, 2, 3, 4, 5)
println(intList.mapNotNull { if (it == 4) null else it * it }) // [1, 4, 9, 25]
源码实现
// 调用mapNotNullTo实现,传入转换函数
public inline fun <T, R : Any> Iterable<T>.mapNotNull(transform: (T) -> R?): List<R> {
return mapNotNullTo(ArrayList<R>(), transform)
}
mapNotNullTo
mapNotNull
的终极实现,将转换后的非空元素添加到集合参数中
val intList = listOf(1, 2, 3, 4, 5)
val hashSet = hashSetOf<Int>()
println(intList.mapNotNullTo(hashSet) { if (it == 4) null else it * it }) // [1, 4, 9, 25]
源码实现
// forEach遍历元素,将元素根据转换函数进行转换,将转换之后的非空元素添加到集合
public inline fun <T, R : Any, C : MutableCollection<in R>> Iterable<T>.mapNotNullTo(destination: C, transform: (T) -> R?): C {
forEach { element -> transform(element)?.let { destination.add(it) } }
return destination
}
mapTo
map
的终极实现,将转换后的元素添加到集合参数中
val intList = listOf(1, 2, 3, 4, 5)
val nestList = listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6, 7))
println(intList.mapTo(hashSetOf()) { it * it })
println(nestList.mapTo(hashSetOf()) { item -> item.map { it * it } })
源码实现
// 转换函数进行转换后添加到集合,会修改传进来的集合参数
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
}
minus
获取两个集合中的差值,或者集合中去除某个元素,返回 List
。
val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
val finalFourBy2022 = listOf("凯尔特人", "勇士", "热火", "独行侠")
println(finalFourBy2023.minus(finalFourBy2022)) // [湖人, 掘金]
println(finalFourBy2023 - finalFourBy2022) // 跟上面的表述是一样的,因为minus是一个操作符operator
println(finalFourBy2023.minus("热火")) // [凯尔特人, 湖人, 掘金]
println(finalFourBy2023 - "热火") // 跟上面的表述是一样的,因为minus是一个操作符operator
源码实现
// 实际是通过filterNot过滤掉在另一个集合中的元素
public operator fun <T> Iterable<T>.minus(elements: Iterable<T>): List<T> {
val other = elements.convertToListIfNotCollection()
if (other.isEmpty())
return this.toList()
return this.filterNot { it in other }
}
// 通过filterTo过滤掉元素,过滤完后将removed置为true
public operator fun <T> Iterable<T>.minus(element: T): List<T> {
val result = ArrayList<T>(collectionSizeOrDefault(10))
var removed = false
return this.filterTo(result) { if (!removed && it == element) { removed = true; false } else true }
}
none
判断集合中是否不存在满足条件的元素,返回值为 Boolean
,如果存在返回 false
,如果不存在返回 true
,与 any
刚好相反
例如判断集合中是否不存在偶数或者大于6
val intList = listOf(1, 2, 3, 4, 5)
println(intList.none { it % 2 == 0 }) // false
println(intList.none { it > 6 }) // true
源码实现
// 集合为空就返回true
// for循环遍历,满足条件就返回false了
// 源码跟any函数刚好相反
public inline fun <T> Iterable<T>.none(predicate: (T) -> Boolean): Boolean {
if (this is Collection && isEmpty()) return true
for (element in this) if (predicate(element)) return false
return true
}
// 集合是空就返回true
public fun <T> Iterable<T>.none(): Boolean {
if (this is Collection) return isEmpty()
return !iterator().hasNext()
}
onEach
遍历整个集合,与 forEach
不同的是,onEach
返回集合本身,所以我们使用 onEach
之后可以继续调用链式调用集合操作符
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
company.onEach { println(it) } // 输出整个集合
.filter { it.length > 5 } // 过滤元素
源码实现
// 通过apply函数遍历集合,关于apply函数大家可以去学习下,主要是apply、let、run、with和also,apply会返回对象本身
public inline fun <T, C : Iterable<T>> C.onEach(action: (T) -> Unit): C {
return apply { for (element in this) action(element) }
}
onEachIndexed
遍历整个集合,与 onEach
不同的是会在 lambda
中对一个 index
索引参数
val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
company.onEachIndexed { index, item -> if (index != 3) println(item) } // 输出除了apple外的所有元素
.filter { it.length > 5 } // // 过滤元素
源码实现
// forEachIndexed遍历
public inline fun <T, C : Iterable<T>> C.onEachIndexed(action: (index: Int, T) -> Unit): C {
return apply { forEachIndexed(action) }
}
partition
将集合进行分类,满足条件和不满足条件的,返回 Pair
,类型是 List
。说实话 我没怎么用过 Pair
,看了下 Pair
才知道是数据类型
public data class Pair<out A, out B>(
public val first: A,
public val second: B
) : Serializable {
/**
* Returns string representation of the [Pair] including its [first] and [second] values.
*/
public override fun toString(): String = "($first, $second)"
}
例如我们需要将小伙伴根据性别进行分类,非男即女嘛
val names = listOf("陈女士", "张先生", "王先生", "蔡女士", "李先生", "钟女士", "朱先生")
val pair = names.partition { it.endsWith("先生") }
println(pair.first) // [张先生, 王先生, 李先生, 朱先生]
println(pair.second) // [陈女士, 蔡女士, 钟女士]
源码实现
// for循环遍历,将满足条件的添加到first,否则添加到second
// 返回pair数据类型,传进first和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)
}
plus
获取两个集合中的总和,或者集合中添加某个元素,返回 List
。如果要保证元素唯一,请使用 set
val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
val finalFourBy2022 = listOf("凯尔特人", "勇士", "热火", "独行侠")
println(finalFourBy2023.plus(finalFourBy2022)) // [凯尔特人, 热火, 湖人, 掘金, 凯尔特人, 勇士, 热火, 独行侠]
println(finalFourBy2023 + finalFourBy2022) // 跟上面的表述一样,因为plus是一个操作符operator
println(finalFourBy2023.plus("热火")) // [凯尔特人, 热火, 湖人, 掘金, 热火]
println(finalFourBy2023 + "热火") // 跟上面的表述一样,因为plus是一个操作符operator
源码实现
// 如果是Collection,则调用它的plus方法 public operator fun <T> Iterable<T>.plus(elements: Iterable<T>): List<T> { if (this is Collection) return this.plus(elements) val result = ArrayList<T>() result.addAll(this) result.addAll(elements) return result } // 添加的集合是Collection,则获取集合的长度,然后添加集合总值 public operator fun <T> Collection<T>.plus(elements: Iterable<T>): List<T> { if (elements is Collection) { val result = ArrayList<T>(this.size + elements.size) result.addAll(this) result.addAll(elements) return result } else { val result = ArrayList<T>(this) result.addAll(elements) return result } } // 添加单个元素 public operator fun <T> Iterable<T>.plus(elements: Array<out T>): List<T> { if (this is Collection) return this.plus(elements) val result = ArrayList<T>() result.addAll(this) result.addAll(elements) return result } // 添加单个元素 public operator fun <T> Collection<T>.plus(element: T): List<T> { val result = ArrayList<T>(size + 1) result.addAll(this) result.add(element) return result }
plusElement
添加某个元素到集合中,不是操作符,所以不能使用 “+”,其内部也是通过 plus
实现
源码实现
public inline fun <T> Iterable<T>.plusElement(element: T): List<T> {
return plus(element)
}
random
和 randomOrNull
随机获取某个元素,与我们常用的 random
差不多意思,如果集合为空, random
抛出 NoSuchElementException
异常,randomOrNull
返回空,只作用于 Collection
。其实实现原理很简单,就是随机拿到索引,然后通过索引返回元素
源码实现
public fun <T> Collection<T>.random(random: Random): T {
if (isEmpty())
throw NoSuchElementException("Collection is empty.")
return elementAt(random.nextInt(size))
}
public fun <T> Collection<T>.randomOrNull(random: Random): T? {
if (isEmpty())
return null
return elementAt(random.nextInt(size))
}
reduce
对集合中的每个元素进行操作,返回积累的总值。与 fold
不同的是,reduce
不需要传入初始值,并且如果集合为空,则抛出 UnsupportedOperationException
异常,可以使用 reduceOrNull
代替
val intList = listOf(1, 2, 3, 4, 5)
println(emptyList<Int>().reduce { acc, item -> acc + item }) // java.lang.UnsupportedOperationException
println(intList.reduce { acc, item -> acc + item }) // 15
println(intList.reduce { acc, item -> acc + item * item }) // 55
源码实现
// 通过迭代器迭代集合,如果为空则抛出UnsupportedOperationException异常
// 首次accumulator是首个元素,将accumulator传入下一次操作中
public inline fun <S, T : S> Iterable<T>.reduce(operation: (acc: S, T) -> S): S {
val iterator = this.iterator()
if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.")
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(accumulator, iterator.next())
}
return accumulator
}
reduceIndexed
与 reduce
一样,只是 lambda
中多了个 index
索引参数,index
从 1 开始的,不是从 0 开始
val intList = listOf(1, 2, 3, 4, 5)
println(emptyList<Int>().reduceIndexed { index, acc, item -> acc + item }) // java.lang.UnsupportedOperationException
println(intList.reduceIndexed { index, acc, item -> if (index != 1) acc + item else acc * item }) // 14
println(intList.reduceIndexed { index, acc, item -> acc + item * item }) // 55
源码实现
// 通过迭代器迭代集合,如果为空则抛出UnsupportedOperationException异常
// 首次accumulator是首个元素,将accumulator传入下一次操作中
// 注意看这里初始index是1,为什么是1?因为第一次取值已经拿出首个元素了
public inline fun <S, T : S> Iterable<T>.reduceIndexed(operation: (index: Int, acc: S, T) -> S): S {
val iterator = this.iterator()
if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.")
var index = 1
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(checkIndexOverflow(index++), accumulator, iterator.next())
}
return accumulator
}
reduceIndexedOrNull
与 reduceIndexed
一样,只是集合为空的时候返回 null
val intList = listOf(1, 2, 3, 4, 5)
println(emptyList<Int>().reduceIndexedOrNull { index, acc, item -> acc + item }) // null
println(intList.reduceIndexedOrNull { index, acc, item -> if (index != 1) acc + item else acc * item }) // 14
println(intList.reduceIndexedOrNull { index, acc, item -> acc + item * item }) // 55
源码实现
// 通过迭代器迭代集合,如果为空则返回null
// 首次accumulator是首个元素,将accumulator传入下一次操作中
// 注意看这里初始index是1,为什么是1?因为第一次取值已经拿出首个元素了
public inline fun <S, T : S> Iterable<T>.reduceIndexedOrNull(operation: (index: Int, acc: S, T) -> S): S? {
val iterator = this.iterator()
if (!iterator.hasNext()) return null
var index = 1
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(checkIndexOverflow(index++), accumulator, iterator.next())
}
return accumulator
}
reduceOrNull
与 reduce
一样,只是集合为空的时候返回 null
val intList = listOf(1, 2, 3, 4, 5)
println(emptyList<Int>().reduceOrNull { acc, item -> acc + item }) // null
println(intList.reduceOrNull { acc, item -> acc + item }) // 15
println(intList.reduceOrNull { acc, item -> acc + item * item }) // 55
源码实现
// 集合为空则返回null
public inline fun <S, T : S> Iterable<T>.reduceOrNull(operation: (acc: S, T) -> S): S? {
val iterator = this.iterator()
if (!iterator.hasNext()) return null
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(accumulator, iterator.next())
}
return accumulator
}
reduceRight
对集合中的每个元素进行操作,返回积累的总值。与 reduce
不同的是,reduceRight
是从右到左积累,reduce
是从左到右积累。因为是有顺序的,所以只作用于 list
。
注意 这里的 lambda
表达式的第一个参数是元素,第二个参数是上一次操作的值
val intList = listOf(1, 2, 3, 4, 5)
println(emptyList<Int>().reduceRight { item, acc -> acc + item }) // java.lang.UnsupportedOperationException
println(intList.reduceRight { item, acc -> acc + item }) // 15
println(intList.reduceRight { item, acc -> acc + item * item }) // 35
源码实现
// 使用listIterator迭代器遍历
public inline fun <S, T : S> List<T>.reduceRight(operation: (T, acc: S) -> S): S {
val iterator = listIterator(size)
if (!iterator.hasPrevious())
throw UnsupportedOperationException("Empty list can't be reduced.")
var accumulator: S = iterator.previous()
while (iterator.hasPrevious()) {
accumulator = operation(iterator.previous(), accumulator)
}
return accumulator
}
reduceRightIndexed
与 reduceRight
一样,只是 lambda
中多了个 index
索引参数
注意 这里的 lambda
表达式的第一个参数是索引,第二个参数是元素,第三个参数是上一次操作的值
val intList = listOf(1, 2, 3, 4, 5)
println(emptyList<Int>().reduceRightIndexed { index, item, acc -> acc + item }) // java.lang.UnsupportedOperationException
println(intList.reduceRightIndexed { index, item, acc -> acc + item }) // 15
println(intList.reduceRightIndexed { index, item, acc -> acc + item * item }) // 35
源码实现
// 使用listIterator迭代器遍历
public inline fun <S, T : S> List<T>.reduceRightIndexed(operation: (index: Int, T, acc: S) -> S): S {
val iterator = listIterator(size)
if (!iterator.hasPrevious())
throw UnsupportedOperationException("Empty list can't be reduced.")
var accumulator: S = iterator.previous()
while (iterator.hasPrevious()) {
val index = iterator.previousIndex()
accumulator = operation(index, iterator.previous(), accumulator)
}
return accumulator
}
reduceRightIndexedOrNull
与 reduceRightIndexed
一样,只是集合为空的时候返回 null
val intList = listOf(1, 2, 3, 4, 5)
println(emptyList<Int>().reduceRightIndexedOrNull { index, item, acc -> acc + item }) // null
println(intList.reduceRightIndexedOrNull { index, item, acc -> acc + item }) // 15
println(intList.reduceRightIndexedOrNull { index, item, acc -> acc + item * item }) // 35
源码实现
// 使用listIterator迭代器遍历
// 集合为空时返回null
public inline fun <S, T : S> List<T>.reduceRightIndexedOrNull(operation: (index: Int, T, acc: S) -> S): S? {
val iterator = listIterator(size)
if (!iterator.hasPrevious())
return null
var accumulator: S = iterator.previous()
while (iterator.hasPrevious()) {
val index = iterator.previousIndex()
accumulator = operation(index, iterator.previous(), accumulator)
}
return accumulator
}
reduceRightOrNull
与 reduceRight
一样,只是集合为空的时候返回 null
val intList = listOf(1, 2, 3, 4, 5)
println(emptyList<Int>().reduceRightOrNull { item, acc -> acc + item }) // null
println(intList.reduceRightOrNull { item, acc -> acc + item }) // 15
println(intList.reduceRightOrNull { item, acc -> acc + item * item }) // 35
源码实现
// 使用listIterator迭代器遍历
// 集合为空时返回null
public inline fun <S, T : S> List<T>.reduceRightOrNull(operation: (T, acc: S) -> S): S? {
val iterator = listIterator(size)
if (!iterator.hasPrevious())
return null
var accumulator: S = iterator.previous()
while (iterator.hasPrevious()) {
accumulator = operation(iterator.previous(), accumulator)
}
return accumulator
}
requireNoNulls
如果集合中存在 null
元素,抛出 IllegalArgumentException
异常,否则返回一个不包含 null
元素 的集合
val random = listOf<Any?>("蔡徐坤", 2.5f, "唱跳rap", null)
val intList = listOf(1, 2, 3, 4, 5)
println(intList.requireNoNulls()) // [1, 2, 3, 4, 5]
println(random.requireNoNulls()) // java.lang.IllegalArgumentException
源码实现
// 很简单,for循环遍历,如果有null则跑出异常,否则强转类型 public fun <T : Any> Iterable<T?>.requireNoNulls(): Iterable<T> { for (element in this) { if (element == null) { throw IllegalArgumentException("null element found in $this.") } } @Suppress("UNCHECKED_CAST") return this as Iterable<T> } public fun <T : Any> List<T?>.requireNoNulls(): List<T> { for (element in this) { if (element == null) { throw IllegalArgumentException("null element found in $this.") } } @Suppress("UNCHECKED_CAST") return this as List<T> }
reversed
反序集合,返回 List
val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
println(finalFourBy2023.reversed()) // [掘金, 湖人, 热火, 凯尔特人]
源码实现
// 长度小于1,返回toList,否则toMutableList
public fun <T> Iterable<T>.reversed(): List<T> {
if (this is Collection && size <= 1) return toList()
val list = toMutableList()
list.reverse()
return list
}
// reverse 拓展函数,expect好像是跨平台函数实现?作者没找到具体实现是哪,有小伙伴知道可以告诉下
public expect fun <T> MutableList<T>.reverse(): Unit
runningFold
从左到右进行累加值,并将每一次执行之后的累计值放进集合中,返回的是 List
,需要传入初始值。与 Fold
本质区别在于,Fold
是返回累加值的总值,而 runningFold
是将每个累加值都添加到 List
中返回。如果集合为空,则返回只带有初始值的 List
val intList = listOf(1, 2, 3, 4, 5)
println(intList.runningFold(0) { prev, item -> prev + item }) // [0, 1, 3, 6, 10, 15]
println(intList.runningFold(0) { prev, item -> prev + item * item }) // [0, 1, 5, 14, 30, 55]
源码实现
// collectionSizeOrDefault获取的是集合的长度 // 为什么ArrayList的长度是estimatedSize + 1?因为它还有个初始值,初始值是直接加入到ArrayList的 // 每执行一次函数,就值放入到ArrayList中,最后返回 public inline fun <T, R> Iterable<T>.runningFold(initial: R, operation: (acc: R, T) -> R): List<R> { val estimatedSize = collectionSizeOrDefault(9) if (estimatedSize == 0) return listOf(initial) val result = ArrayList<R>(estimatedSize + 1).apply { add(initial) } var accumulator = initial for (element in this) { accumulator = operation(accumulator, element) result.add(accumulator) } return result } internal fun <T> Iterable<T>.collectionSizeOrDefault(default: Int): Int = if (this is Collection<*>) this.size else default
runningFoldIndexed
与 runningFold
一样,只是 lambda
多了个 index
索引参数
val intList = listOf(1, 2, 3, 4, 5)
println(intList.runningFoldIndexed(0) { index, prev, item -> if (index == 0) prev + item else prev + item * item }) // [0, 1, 5, 14, 30, 55]
println(intList.runningFoldIndexed(0) { index, prev, item -> if (index == 0) prev + item * item else prev * item * item }) // [0, 1, 4, 36, 576, 14400]
源码实现
// collectionSizeOrDefault获取的是集合的长度 // 为什么ArrayList的长度是estimatedSize + 1?因为它还有个初始值,初始值是直接加入到ArrayList的 // 每执行一次函数,就值放入到ArrayList中,最后返回 public inline fun <T, R> Iterable<T>.runningFoldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): List<R> { val estimatedSize = collectionSizeOrDefault(9) if (estimatedSize == 0) return listOf(initial) val result = ArrayList<R>(estimatedSize + 1).apply { add(initial) } var index = 0 var accumulator = initial for (element in this) { accumulator = operation(index++, accumulator, element) result.add(accumulator) } return result } internal fun <T> Iterable<T>.collectionSizeOrDefault(default: Int): Int = if (this is Collection<*>) this.size else default
runningReduce
从左到右进行累加值,并将每一次执行之后的累计值放进集合中,返回的是 List
。与 reduce
本质区别在于,reduce
是返回累加值的总值,而 runningReduce
是将每个累加值都添加到 List
中返回。与 runningFold
的区别在于, runningReduce
不需要传入初始值,如果集合为空则直接返回空集合
val intList = listOf(1, 2, 3, 4, 5)
println(emptyList<Int>().runningReduce { acc, item -> acc + item }) // []
println(intList.runningReduce { acc, item -> acc + item }) // [1, 3, 6, 10, 15]
println(intList.runningReduce { acc, item -> acc + item * item }) // [1, 5, 14, 30, 55]
源码实现
// 空集合则直接返回emptyList
// 这里将集合中的首个元素当做了初始值,并添加到集合中
public inline fun <S, T : S> Iterable<T>.runningReduce(operation: (acc: S, T) -> S): List<S> {
val iterator = this.iterator()
if (!iterator.hasNext()) return emptyList()
var accumulator: S = iterator.next()
val result = ArrayList<S>(collectionSizeOrDefault(10)).apply { add(accumulator) }
while (iterator.hasNext()) {
accumulator = operation(accumulator, iterator.next())
result.add(accumulator)
}
return result
}
runningReduceIndexed
与 runningReduce
一样,只是 lambda
中多了个 index
索引参数
val intList = listOf(1, 2, 3, 4, 5)
println(emptyList<Int>().runningReduceIndexed { index, acc, item -> if (index == 1) acc + item else acc * item }) // []
println(intList.runningReduceIndexed { index, acc, item -> if (index == 1) acc + item else acc * item }) // [1, 3, 9, 36, 180]
println(intList.runningReduceIndexed { index, acc, item -> if (index == 1) acc + item * item else acc * item * item }) // [1, 5, 45, 720, 18000]
源码实现
// 空集合则直接返回emptyList
// 这里将集合中的首个元素当做了初始值,并添加到集合中
// 注意这里的index是从1开始的,因为首次已经将索引为0的元素直接添加到集合中了
public inline fun <S, T : S> Iterable<T>.runningReduceIndexed(operation: (index: Int, acc: S, T) -> S): List<S> {
val iterator = this.iterator()
if (!iterator.hasNext()) return emptyList()
var accumulator: S = iterator.next()
val result = ArrayList<S>(collectionSizeOrDefault(10)).apply { add(accumulator) }
var index = 1
while (iterator.hasNext()) {
accumulator = operation(index++, accumulator, iterator.next())
result.add(accumulator)
}
return result
}
scan
与 runningFold
一样都是累加总值返回 List
, 其内部实现就是通过 runningFold
,这里就不多说了
源码实现
public inline fun <T, R> Iterable<T>.scan(initial: R, operation: (acc: R, T) -> R): List<R> {
return runningFold(initial, operation)
}
scanIndexed
与 runningFoldIndexed
一样都是累加总值返回 List
, 其内部实现就是通过 runningFoldIndexed
,这里就不多说了
public inline fun <T, R> Iterable<T>.scanIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): List<R> {
return runningFoldIndexed(initial, operation)
}
shuffle
打乱集合的顺序,随机排列集合元素。
val finalFourBy2023 = setOf("凯尔特人", "热火", "湖人", "掘金")
println(finalFourBy2023.shuffled()) // [湖人, 掘金, 凯尔特人, 热火],每一个都有可能是新的一次排序,这里只是随机了其中一次
源码实现
Kotlin
是直接调用 Java
层的代码实现的,详细看下面
// java.util.Collections
public static void shuffle(List<?> list) {
Random rnd = r;
if (rnd == null)
r = rnd = new Random(); // harmless race.
shuffle(list, rnd);
}
当然,Kotlin
也有自己的实现,不过返回的是 Unit
,我们稍微看一下
// 倒序遍历,也是通过random实现
// this[j] = this.set(i, this[j]) 是交换两个元素的位置
public fun <T> MutableList<T>.shuffle(random: Random): Unit {
for (i in lastIndex downTo 1) {
val j = random.nextInt(i + 1)
this[j] = this.set(i, this[j])
}
}
single
判断集合中有且只有一个元素满足条件,如果有多个元素满足条件则抛出 IllegalArgumentException
异常,如果没有元素满足条件则抛出 NoSuchElementException
异常,最终返回该元素
val finalFourBy2023 = setOf("凯尔特人", "热火", "湖人", "掘金")
println(finalFourBy2023.single { it.length > 2 }) // 凯尔特人
println(finalFourBy2023.single { it.endsWith("人") }) // java.lang.IllegalArgumentException
println(finalFourBy2023.single { it == "太阳" }) // // java.util.NoSuchElementException
源码实现
// 通过found的值去判断,如果满足条件并且found为true则抛出IllegalArgumentException // 遍历完集合后,found如果为false则抛出NoSuchElementException public inline fun <T> Iterable<T>.single(predicate: (T) -> Boolean): T { var single: T? = null var found = false for (element in this) { if (predicate(element)) { if (found) throw IllegalArgumentException("Collection contains more than one matching element.") single = element found = true } } if (!found) throw NoSuchElementException("Collection contains no element matching the predicate.") @Suppress("UNCHECKED_CAST") return single as T } // single的重载函数,不需要传入函数类型的参数 // 这个就简单多了,如果集合为空则抛出NoSuchElementException // 如果集合长度大于1,则抛出IllegalArgumentException public fun <T> Iterable<T>.single(): T { when (this) { is List -> return this.single() else -> { val iterator = iterator() if (!iterator.hasNext()) throw NoSuchElementException("Collection is empty.") val single = iterator.next() if (iterator.hasNext()) throw IllegalArgumentException("Collection has more than one element.") return single } } }
singleOrNull
判断集合中有且只有一个元素满足条件,如果有多个元素满足条件或者没有元素满足条件则返回 null
val finalFourBy2023 = setOf("凯尔特人", "热火", "湖人", "掘金")
println(finalFourBy2023.singleOrNull { it.length > 2 }) // 凯尔特人
println(finalFourBy2023.singleOrNull { it.endsWith("人") }) // null
println(finalFourBy2023.singleOrNull { it == "太阳" }) // null
源码实现
// 与 single 的源码差不多,只是把single抛出异常的地方换成了返回null public inline fun <T> Iterable<T>.singleOrNull(predicate: (T) -> Boolean): T? { var single: T? = null var found = false for (element in this) { if (predicate(element)) { if (found) return null single = element found = true } } if (!found) return null return single } // 这个重载函数就不用说了吧,根据集合元素个数判断,只有1个元素才返回值,否则返回null public fun <T> Iterable<T>.singleOrNull(): T? { when (this) { is List -> return if (size == 1) this[0] else null else -> { val iterator = iterator() if (!iterator.hasNext()) return null val single = iterator.next() if (iterator.hasNext()) return null return single } } }
slice
这个一听单词就知道是切割的作用,主要是切割集合后返回切割之后的所有元素,返回的是 List
,只作用于 List
,(插句话:不知道大家有没试过切割数组?)
slice
有两个重载函数,一个是传入 IntRange
,一个是传入索引的集合。一般来说用 IntRange
的更多,毕竟需要切割获取连续值多点嘛
注意 IntRange
是两头闭区间
例如我们需要前三个元素的集合,可以这样做
val names = listOf("陈女士", "张先生", "王先生", "蔡女士", "李先生", "钟女士", "朱先生")
println(names.slice(IntRange(0, 2))) // [陈女士, 张先生, 王先生]
println(names.slice(0..2)) // 等价与上面的IntRange(0, 2),0..2是一个极简的表达
println(names.slice(listOf(0, 1, 2))) // [陈女士, 张先生, 王先生]
或者我们需要随机获取集合,可以这样做
val names = listOf("陈女士", "张先生", "王先生", "蔡女士", "李先生", "钟女士", "朱先生")
println(names.slice(listOf(0, 5, 4, 3))) // [陈女士, 钟女士, 李先生, 蔡女士]
println(names.slice(listOf(0, 5, 7, 3, 9))) // java.lang.ArrayIndexOutOfBoundsException
注意 不管是 IntRange
还是 索引的集合,都需要在集合的有效索引内即[0, lastIndex],否则会出现数组越界
源码实现
// 如果是空,则返回空集合 // 为什么需要indices.endInclusive + 1? // 因为IntRange是两头闭区间[start, end],subList获取的是开区间[start, end) // 注意数组越界问题 public fun <T> List<T>.slice(indices: IntRange): List<T> { if (indices.isEmpty()) return listOf() return this.subList(indices.start, indices.endInclusive + 1).toList() } // 根据索引获取元素,然后添加到List中 // 注意数组越界问题 public fun <T> List<T>.slice(indices: Iterable<Int>): List<T> { val size = indices.collectionSizeOrDefault(10) if (size == 0) return emptyList() val list = ArrayList<T>(size) for (index in indices) { list.add(get(index)) } return list }
sortBy
根据函数类型参数的返回值进行排序集合,其实是通过 ASCII
值排序。会修改原集合,返回的是 Unit
,只作用于 MutableList
,MutableList
与 List
的区别?MutableList
可以 curd
,List
只能获取和遍历
例如根据姓名或者年龄排序
data class Person(val name: String, val age: Int)
val virtualPeoples = mutableListOf(
Person(name = "陈女士", age = 18),
Person(name = "王先生", age = 28),
Person(name = "王小姐", age = 23),
Person(name = "陈先生", age = 33),
)
virtualPeoples.sortBy { it.name }
println(virtualPeoples) // [Person(name=王先生, age=28), Person(name=王小姐, age=23), Person(name=陈先生, age=33), Person(name=陈女士, age=18)]
virtualPeoples.sortBy { it.age }
println(virtualPeoples) // [Person(name=陈女士, age=18), Person(name=王小姐, age=23), Person(name=王先生, age=28), Person(name=陈先生, age=33)]
源码实现
// 通过sortWith排序
public inline fun <T, R : Comparable<R>> MutableList<T>.sortBy(crossinline selector: (T) -> R?): Unit {
if (size > 1) sortWith(compareBy(selector))
}
sortByDescending
与 sortBy
类似,只是 sortBy
是升序,sortByDescending
是降序
data class Person(val name: String, val age: Int)
val virtualPeoples = mutableListOf(
Person(name = "陈女士", age = 18),
Person(name = "王先生", age = 28),
Person(name = "王小姐", age = 23),
Person(name = "陈先生", age = 33),
)
virtualPeoples.sortByDescending { it.name }
println(virtualPeoples) // [Person(name=陈女士, age=18), Person(name=陈先生, age=33), Person(name=王小姐, age=23), Person(name=王先生, age=28)]
virtualPeoples.sortByDescending { it.age }
println(virtualPeoples) // [Person(name=陈先生, age=33), Person(name=王先生, age=28), Person(name=王小姐, age=23), Person(name=陈女士, age=18)]
源码实现
// 通过sortWith排序
public inline fun <T, R : Comparable<R>> MutableList<T>.sortByDescending(crossinline selector: (T) -> R?): Unit {
if (size > 1) sortWith(compareByDescending(selector))
}
sortDescending
根据 Comparable
进行降序排序,如果要自定义类支持 sortDescending
,必须继承 Comparable
重写 compareTo
方法
例如我们根据名字和年龄进行排序
data class ComparablePerson(val name: String, val age: Int) : Comparable<ComparablePerson> { override fun compareTo(other: ComparablePerson): Int { return if (name == other.name) { age - other.age } else { name.compareTo(other.name) } } } val virtualPeoples = mutableListOf( ComparablePerson(name = "陈女士", age = 18), ComparablePerson(name = "王先生", age = 28), ComparablePerson(name = "王小姐", age = 23), ComparablePerson(name = "陈女士", age = 33), ) virtualPeoples.sortDescending() println(virtualPeoples) // [ComparablePerson(name=陈女士, age=33), ComparablePerson(name=陈女士, age=18), ComparablePerson(name=王小姐, age=23), ComparablePerson(name=王先生, age=28)]
源码实现
// sortWith,传入reverseOrder,我们可以大胆猜测就是reverseOrder是的排序降序的
public fun <T : Comparable<T>> MutableList<T>.sortDescending(): Unit {
sortWith(reverseOrder())
}
sorted
根据 Comparable
进行升序排序,如果要自定义类支持 sorted
,必须继承 Comparable
重写 compareTo
方法。
注意 与 sortByxxx
不同的是,sortedxxx
不会修改原集合,而是返回一个新的集合
data class ComparablePerson(val name: String, val age: Int) : Comparable<ComparablePerson> { override fun compareTo(other: ComparablePerson): Int { return if (name == other.name) { age - other.age } else { name.compareTo(other.name) } } } val virtualPeoples = mutableListOf( ComparablePerson(name = "陈女士", age = 18), ComparablePerson(name = "王先生", age = 28), ComparablePerson(name = "王小姐", age = 23), ComparablePerson(name = "陈女士", age = 33), ) println(virtualPeoples.sorted()) // [ComparablePerson(name=王先生, age=28), ComparablePerson(name=王小姐, age=23), ComparablePerson(name=陈女士, age=18), ComparablePerson(name=陈女士, age=33)] println(virtualPeoples) // [ComparablePerson(name=陈女士, age=18), ComparablePerson(name=王先生, age=28), ComparablePerson(name=王小姐, age=23), ComparablePerson(name=陈女士, age=33)]
源码实现
// 如果是Collection,通过数组来进行排序后转为List
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() }
// 貌似是跨平台的实现?
expect fun <T : Comparable<T>> MutableList<T>.sort(): Unit
sortedBy
根据函数类型参数的返回值进行升序排序集合
注意 与 sortByxxx
不同的是,sortedxxx
不会修改原集合,而是返回一个新的集合
data class Person(val name: String, val age: Int)
val virtualPeoples = mutableListOf(
Person(name = "陈女士", age = 18),
Person(name = "王先生", age = 28),
Person(name = "王小姐", age = 23),
Person(name = "陈先生", age = 33),
)
println(virtualPeoples.sortedBy { it.age }) // [Person(name=陈女士, age=18), Person(name=王小姐, age=23), Person(name=王先生, age=28), Person(name=陈先生, age=33)]
println(virtualPeoples.sortedBy { it.name }) // [Person(name=王先生, age=28), Person(name=王小姐, age=23), Person(name=陈先生, age=33), Person(name=陈女士, age=18)]
println(virtualPeoples) // [Person(name=陈女士, age=18), Person(name=王先生, age=28), Person(name=王小姐, age=23), Person(name=陈先生, age=33)]
源码实现
// sortedWith实现
public inline fun <T, R : Comparable<R>> Iterable<T>.sortedBy(crossinline selector: (T) -> R?): List<T> {
return sortedWith(compareBy(selector))
}
sortedByDescending
根据函数类型参数的返回值进行降序排序集合,与 sortedBy
刚好相反
注意 与 sortByxxx
不同的是,sortedxxx
不会修改原集合,而是返回一个新的集合
data class Person(val name: String, val age: Int)
val virtualPeoples = mutableListOf(
Person(name = "陈女士", age = 18),
Person(name = "王先生", age = 28),
Person(name = "王小姐", age = 23),
Person(name = "陈先生", age = 33),
)
println(virtualPeoples.sortedByDescending { it.age }) // [Person(name=陈先生, age=33), Person(name=王先生, age=28), Person(name=王小姐, age=23), Person(name=陈女士, age=18)]
println(virtualPeoples.sortedByDescending { it.name }) // [Person(name=陈女士, age=18), Person(name=陈先生, age=33), Person(name=王小姐, age=23), Person(name=王先生, age=28)]
println(virtualPeoples) // [Person(name=陈女士, age=18), Person(name=王先生, age=28), Person(name=王小姐, age=23), Person(name=陈先生, age=33)]
源码实现
public inline fun <T, R : Comparable<R>> Iterable<T>.sortedBy(crossinline selector: (T) -> R?): List<T> {
return sortedWith(compareBy(selector))
}
sortedDescending
根据 Comparable
进行降序排序,如果要自定义类支持 sortedDescending
,必须继承 Comparable
重写 compareTo
方法。
注意 与 sortByxxx
不同的是,sortedxxx
不会修改原集合,而是返回一个新的集合
data class ComparablePerson(val name: String, val age: Int) : Comparable<ComparablePerson> { override fun compareTo(other: ComparablePerson): Int { return if (name == other.name) { age - other.age } else { name.compareTo(other.name) } } } val virtualPeoples = mutableListOf( ComparablePerson(name = "陈女士", age = 18), ComparablePerson(name = "王先生", age = 28), ComparablePerson(name = "王小姐", age = 23), ComparablePerson(name = "陈女士", age = 33), ) println(virtualPeoples.sortedDescending()) // [ComparablePerson(name=陈女士, age=33), ComparablePerson(name=陈女士, age=18), ComparablePerson(name=王小姐, age=23), ComparablePerson(name=王先生, age=28)] println(virtualPeoples) // [ComparablePerson(name=陈女士, age=18), ComparablePerson(name=王先生, age=28), ComparablePerson(name=王小姐, age=23), ComparablePerson(name=陈女士, age=33)]
源码实现
// reverseOrder 降序
public fun <T : Comparable<T>> Iterable<T>.sortedDescending(): List<T> {
return sortedWith(reverseOrder())
}
sortedWith
所有 sortxxx
排序的最终实现,需要传入一个 Comparator
,一般都是用它的上层函数,不怎么会用到这个函数,除非要自定义排序的方式。
例如我这里就是弄了升序和降序两种排序方式
data class Person(val name: String, val age: Int) // 升序 object AscendComparator : Comparator<Person> { override fun compare(o1: Person, o2: Person): Int { return if (o1.name == o2.name) { o1.age - o2.age } else { o1.name.compareTo(o2.name) } } } // 降序 object DescendComparator : Comparator<Person> { override fun compare(o1: Person, o2: Person): Int { return if (o1.name == o2.name) { o2.age - o1.age } else { o2.name.compareTo(o1.name) } } } val virtualPeoples = mutableListOf( Person(name = "陈女士", age = 18), Person(name = "王先生", age = 28), Person(name = "王小姐", age = 23), Person(name = "陈女士", age = 33), ) println(virtualPeoples.sortedWith(AscendComparator)) // [Person(name=王先生, age=28), Person(name=王小姐, age=23), Person(name=陈女士, age=18), Person(name=陈女士, age=33)] println(virtualPeoples.sortedWith { o1, o2 -> if (o1.name == o2.name) { o1.age - o2.age } else { o1.name.compareTo(o2.name) } }) // 同上,只是这里使用了lambda表达式,上面那种更适合在频繁使用的情况下使用 println(virtualPeoples.sortedWith(DescendComparator)) // [Person(name=陈女士, age=33), Person(name=陈女士, age=18), Person(name=王小姐, age=23), Person(name=王先生, age=28)]
源码实现
// 如果是Collection则通过数组进行排序
public fun <T> Iterable<T>.sortedWith(comparator: Comparator<in T>): List<T> {
if (this is Collection) {
if (size <= 1) return this.toList()
@Suppress("UNCHECKED_CAST")
return (toTypedArray<Any?>() as Array<T>).apply { sortWith(comparator) }.asList()
}
return toMutableList().apply { sortWith(comparator) }
}
好累好累~,终于讲完了排序,排序的知识还是蛮多的。插一句话,一般情况下都是 sortByxxx
会多点,它会修改原集合的顺序,而如果你需要返回一个新的集合,则考虑使用 sortedxxx
subtract
返回集合中包含而指定集合中不包含的所有元素(差集),返回的是 set
。从结果上好像和 minus
是一样的,不同的是 minus
返回的是 List
val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
val finalFourBy2022 = listOf("凯尔特人", "勇士", "热火", "独行侠")
println(finalFourBy2023.subtract(finalFourBy2022)) // [湖人, 掘金]
println(finalFourBy2023.minus(finalFourBy2022)) // [湖人, 掘金]
源码实现
// toMutableSet移除removeAll
public infix fun <T> Iterable<T>.subtract(other: Iterable<T>): Set<T> {
val set = this.toMutableSet()
set.removeAll(other)
return set
}
sum
返回集合中的所有元素的总和,因为是累加的所以只作用于 Byte
、Double
、Float
、Int
、Long
、Short
基本类型集合。
这个就不多说了,相信大家都知道是怎么实现的吧。没错,就是常规的 for
循环遍历罢了
随便看下其中一个的源码
public fun Iterable<Byte>.sum(): Int {
var sum: Int = 0
for (element in this) {
sum += element
}
return sum
}
sumOf
与 sum
功能一样,只是它比 sum
多了一步转换,将转换后的元素进行求和。
这里就随便从某个基本类型的集合中抽取一个来做测试
val list = listOf(1, 4, 7, 2, 5, 8, 3, 6, 9)
println(list.sumOf { (it * it) / 2.0 }) // 142.5,这里是将int转为了double
随便看下其中一个的源码
public inline fun <T> Iterable<T>.sumOf(selector: (T) -> Double): Double {
var sum: Double = 0.toDouble()
for (element in this) {
sum += selector(element)
}
return sum
}
take
获取集合中前 n
个元素,如果 n
< 0,则抛出 IllegalArgumentException
异常;如果 n = 0,然后空集合;如果 n > 集合的长度,返回集合的所有元素。返回的是 List
val names = listOf("陈女士", "张先生", "王先生", "蔡女士", "李先生", "钟女士", "朱先生")
println(names.take(-1)) // java.lang.IllegalArgumentException
println(names.take(0)) // []
println(names.take(3)) // [陈女士, 张先生, 王先生]
println(names.take(10)) // [陈女士, 张先生, 王先生, 蔡女士, 李先生, 钟女士, 朱先生]
源码实现
// n<0抛出异常 // n=0 直接返回空集合 // 如果是Collection,n大于长度则返回所有元素,n=1则返回首个元素 // 否则for循环将n之前的元素都加入集合 public fun <T> Iterable<T>.take(n: Int): List<T> { require(n >= 0) { "Requested element count $n is less than zero." } if (n == 0) return emptyList() if (this is Collection<T>) { if (n >= size) return toList() if (n == 1) return listOf(first()) } var count = 0 val list = ArrayList<T>(n) for (item in this) { list.add(item) if (++count == n) break } return list.optimizeReadOnlyList() }
takeLast
获取集合中后 n
个元素,与 take
不同的是,takeLast
是获取末尾的 n 个元素,只作用于 List
,返回的也是 List
val names = listOf("陈女士", "张先生", "王先生", "蔡女士", "李先生", "钟女士", "朱先生")
println(names.takeLast(-1)) // java.lang.IllegalArgumentException
println(names.takeLast(0)) // []
println(names.takeLast(3)) // [李先生, 钟女士, 朱先生]
println(names.takeLast(10)) // [陈女士, 张先生, 王先生, 蔡女士, 李先生, 钟女士, 朱先生]
源码实现
// n<0抛出异常 // n=0 直接返回空集合 // n大于长度则返回所有元素,n=1则返回最后一个元素 // 如果是RandomAccess(例如ArrayList),则for循环遍历,否则listIterator迭代器遍历 public fun <T> List<T>.takeLast(n: Int): List<T> { require(n >= 0) { "Requested element count $n is less than zero." } if (n == 0) return emptyList() val size = size if (n >= size) return toList() if (n == 1) return listOf(last()) val list = ArrayList<T>(n) if (this is RandomAccess) { for (index in size - n until size) list.add(this[index]) } else { for (item in listIterator(size - n)) list.add(item) } return list }
takeLastWhile
获取满足条件的末尾元素,直到元素不满足条件时返回。只作用于 List
,返回的是 List
val list = listOf(1, 4, 7, 2, 5, 8, 3, 6, 9)
println(list.takeLastWhile { it > 5 }) // [6, 9]
println(list.takeLastWhile { it > 0 }) // [1, 4, 7, 2, 5, 8, 3, 6, 9]
println(list.takeLastWhile { it % 2 == 1 }) // [9]
源码实现
// 通过listIterator迭代器遍历,如果某个元素不满足条件,先判断下一个元素的索引是否等于集合长度了,如果是返回emptyList,否则将该元素后面的添加到ArrayList中 // 如果都满足条件,则通过toList返回 public inline fun <T> List<T>.takeLastWhile(predicate: (T) -> Boolean): List<T> { if (isEmpty()) return emptyList() val iterator = listIterator(size) while (iterator.hasPrevious()) { if (!predicate(iterator.previous())) { iterator.next() val expectedSize = size - iterator.nextIndex() if (expectedSize == 0) return emptyList() return ArrayList<T>(expectedSize).apply { while (iterator.hasNext()) add(iterator.next()) } } } return toList() }
takeWhile
获取满足条件的首部元素,直到元素不满足条件时返回。与 takeLastWhile
不同的是,takeWhile
是获取首部满足条件的元素
val list = listOf(1, 4, 7, 2, 5, 8, 3, 6, 9)
println(list.takeWhile { it > 5 }) // []
println(list.takeWhile { it > 0 }) // [1, 4, 7, 2, 5, 8, 3, 6, 9]
println(list.takeWhile { it % 2 == 1 }) // [1]
源码实现
// for循环遍历集合,不满足条件时跳出循环
public inline fun <T> Iterable<T>.takeWhile(predicate: (T) -> Boolean): List<T> {
val list = ArrayList<T>()
for (item in this) {
if (!predicate(item))
break
list.add(item)
}
return list
}
toxxxArray
将xx集合转换成xx数组,主要有 toBooleanArray
、toByteArray
、toCharArray
、toDoubleArray
、toFloatArray
、toIntArray
和 toLongArray
下面就以 toBooleanArray
为例看下使用的场景和源码实现
val permissionGrantMap = linkedMapOf(
Manifest.permission.INTERNET to true,
Manifest.permission.ACCEPT_HANDOVER to false,
Manifest.permission.WRITE_EXTERNAL_STORAGE to false,
Manifest.permission.BLUETOOTH to true
)
val isGrant = permissionGrantMap.values
isGrant.toBooleanArray().onEach {
println(it)
}
源码实现
// 很简单的for循环,就是创建一个BooleanArray长度为集合长度
public fun Collection<Boolean>.toBooleanArray(): BooleanArray {
val result = BooleanArray(size)
var index = 0
for (element in this)
result[index++] = element
return result
}
toxxx
将集合转换为特定的集合,例如 toCollection
转换成 MutableCollection
, toList
转换成 List
。常用的方法有 toList
、toMutableList
、toMutableSet
和 toSet
。
这个就不举例了,相信大家都会使用和看得懂源码
union
获取两个集合的交集,返回 Set
val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
val finalFourBy2022 = listOf("凯尔特人", "勇士", "热火", "独行侠")
println(finalFourBy2023.union(finalFourBy2022)) // [凯尔特人, 热火, 湖人, 掘金, 勇士, 独行侠]
源码实现
// 通过toMutableSet去添加另一个集合
public infix fun <T> Iterable<T>.union(other: Iterable<T>): Set<T> {
val set = this.toMutableSet()
set.addAll(other)
return set
}
windowed
获取集合中从左到右所有给定长度的子集的集合,返回 List<List>
。 可以设置子集的长度 size
;每一个子集之间的间距 step
默认是 1; partialWindows
可以控制末尾的子集的长度是否可以小于 size
,默认是 false
;transform
是用于转换的,需要转换子集的话可以用上这个。size
和 step
都必须大于 0 ,否则抛出 IllegalArgumentException
异常
val list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
println(list.windowed(3)) // [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]
println(list.windowed(3, partialWindows = true)) // [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10], [9, 10], [10]]
println(list.windowed(3, step = 2)) // [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9]]
println(list.windowed(3, step = 2, partialWindows = true)) // [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9], [9, 10]]
// 获取每个子集的和
println(list.windowed(3, step = 2, partialWindows = true, transform = { it.sum() })) // [6, 12, 18, 24, 19]
源码实现
windowed
有两个拓展函数,一个是不带 transform
转换的,一个是有 transform
转换的
// checkWindowSizeStep需要size和step都大于0 // 先根据step获取初始集合的大小 // coerceAtMost是获取两个值的最小值,有点类似于min函数,只是coerceAtMost是拓展函数 // 剩下子集的长度小于size并且partialWindows是false就跳出循环 // 然后创建子集并且初始化子集的元素,最后添加到result中 // 如果不是RandomAccess和List,则通过windowedIterator返回 public fun <T> Iterable<T>.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false): List<List<T>> { checkWindowSizeStep(size, step) if (this is RandomAccess && this is List) { val thisSize = this.size val resultCapacity = thisSize / step + if (thisSize % step == 0) 0 else 1 val result = ArrayList<List<T>>(resultCapacity) var index = 0 while (index in 0 until thisSize) { val windowSize = size.coerceAtMost(thisSize - index) if (windowSize < size && !partialWindows) break result.add(List(windowSize) { this[it + index] }) index += step } return result } val result = ArrayList<List<T>>() windowedIterator(iterator(), size, step, partialWindows, reuseBuffer = false).forEach { result.add(it) } return result }
zip
获取两个集合中相同索引的元素对,为什么我称它为元素对,因为它是从一个集合中取出元素,又从另一个集合中取出该元素的索引的元素,在 Kotlin
用 Pair
形容这个元素对。所以返回值是 Pair
的集合,即 List<Pair>
。当然你也可以使用 transform
返回自己想要的值,而不是元素对 Pair
val finalFourBy2023 = listOf("掘金", "热火", "凯尔特人", "湖人")
val finalSort = listOf(1, 2, 3, 4, 5, 6, 7, 8)
println(finalFourBy2023.zip(finalSort)) // [(1, 掘金), (2, 热火), (3, 凯尔特人), (4, 湖人)]
println(finalFourBy2023.zip(finalSort) { a, b -> "$a -> $b" }) // [掘金 -> 1, 热火 -> 2, 凯尔特人 -> 3, 湖人 -> 4]
源码实现
public infix fun <T, R> Iterable<T>.zip(other: Iterable<R>): List<Pair<T, R>> {
return zip(other) { t1, t2 -> t1 to t2 }
}
// minOf获取返回集合的长度,因为很多时候两个集合的长度是不对等的,所以返回最短的那个
// 通过迭代器去将索引一样的元素进行转换后添加到集合中
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
}
zipWithNext
返回集合中相邻元素的元素对,如果集合长度小于2,返回空集合。返回值是 Pair
的集合,即 List<Pair>
。当然你也可以使用 transform
返回自己想要的值,而不是元素对 Pair
val championsBy2023 = listOf("掘金")
val finalFourBy2023 = listOf("掘金", "热火", "凯尔特人", "湖人")
println(championsBy2023.zipWithNext()) // []
println(finalFourBy2023.zipWithNext()) // [(掘金, 热火), (热火, 凯尔特人), (凯尔特人, 湖人)]
println(finalFourBy2023.zipWithNext { a, b -> "$a -> $b" }) // [掘金 -> 热火, 热火 -> 凯尔特人, 凯尔特人 -> 湖人]
源码实现
public fun <T> Iterable<T>.zipWithNext(): List<Pair<T, T>> { return zipWithNext { a, b -> a to b } } // 集合为空或者长度小于2都会返回空集合 // 通过迭代器迭代,先转换元素后添加到集合中 public inline fun <T, R> Iterable<T>.zipWithNext(transform: (a: T, b: T) -> R): List<R> { val iterator = iterator() if (!iterator.hasNext()) return emptyList() val result = mutableListOf<R>() var current = iterator.next() while (iterator.hasNext()) { val next = iterator.next() result.add(transform(current, next)) current = next } return result }
终于把集合操作符都讲完了,大概是用了5天的时间吧,把所有的操作符从头到尾的讲了一遍,特别是源码方面的东西,我个人还是第一次这么深层次的去看 Kotlin
的源码实现。怎么说呢,学习源码对自己的提升肯定是有的,特别是对算法效率提升方面的提升。我工作了五年,也是第一次写这么一篇长篇大论,感觉还是挺累的,不过累并快乐着~。接下来有计划把字符串或者 Map
的操作符也一并干碎,如果喜欢的话可以给个点赞哈,当然文中可能还有一些不足的地方,欢迎小伙伴在底下留言评论 华山论剑 。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。