当前位置:   article > 正文

Kotlin 集合操作符

kotlin 集合操作符

集合操作符

今天介绍下 Kotlin 集合中的操作符,本文中 Kotlin 所用版本是 1.8.10

大部分的操作符是使用内联实现的,如果对内联函数感兴趣,可以康康我的这篇文章,Kotlin inline内联函数

all

判断集合中的所有元素是否满足需求,返回值为 Boolean

例如我们需要判断字符串的长度是否大于4

val songs = listOf("一路向北", "搁浅", "最长的电影")
songs.all { it.length >= 4 } // false
  • 1
  • 2

源码实现

// 继承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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

any

判断集合中是否存在满足条件的元素,返回值为 Boolean

例如我们需要判断是否存在185cm 8块腹肌以上的小哥哥

val heights = listOf(188, 165, 175)
heights.any { it >= 185 } // true
  • 1
  • 2

源码实现

// 继承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()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

contains

集合是否包含某个元素,返回为 Boolean

例如判断班上是否有个名叫蔡徐坤的童鞋

val nickname = listOf("蔡徐坤", "坤蔡徐", "蔡坤徐", "蔡徐坤")
println(nickname.contains("蔡徐坤"))  // true
  • 1
  • 2

源码实现

// 继承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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

count

返回集合中的长度

val nickname = listOf("蔡徐坤", "坤蔡徐", "蔡坤徐", "蔡徐坤")
println(nickname.count()) // 4
  • 1
  • 2

源码实现

// 继承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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

根据条件返回集合中满足条件的所有元素长度

例如我们需要统计班上的童鞋身高达到 185cm 的人数

val height = listOf(188, 165, 175, 185)
println(height.count { it >= 185 } ) // 2
  • 1
  • 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

distinct

过滤掉集合中相同的元素,返回一个新集合,实际是通过 HashSet 保证元素不重复

例如过滤掉重名的同学

val nickname = listOf("蔡徐坤", "坤蔡徐", "蔡坤徐", "蔡徐坤")
nickname.distinct()  // [蔡徐坤, 坤蔡徐, 蔡坤徐]
  • 1
  • 2

源码实现

public fun <T> Iterable<T>.distinct(): List<T> {
    return this.toMutableSet().toList()
}
  • 1
  • 2
  • 3

distinctBy

根据条件过滤掉集合中的元素,返回一个新集合,实际是通过 HashSet 保证元素不重复

例如根据名字长度过滤

val nickname = listOf("蔡徐坤", "蔡", "坤蔡徐", "蔡坤徐", "蔡徐")
nickname.distinctBy { it.length } // [蔡徐坤, 蔡, 蔡徐]
  • 1
  • 2

如果想实现 distinct 过滤相同的元素,这样写即可(那还不如直接用 distinct 呢)

nickname.distinctBy { it }
  • 1

源码实现

// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

drop

过滤集合中前 n 个 元素,返回新的集合。n < 0 时抛出 IllegalArgumentException 异常,n = 0 时返回原集合,n >= 集合长度时返回空集合

val heroName = listOf("蛮三刀", "托儿索", "儿童劫", "提款姬", "菊花信")
println(heroName.drop(0)) // [蛮三刀, 托儿索, 儿童劫, 提款姬, 菊花信]
println(heroName.drop(2)) // [儿童劫, 提款姬, 菊花信]
println(heroName.drop(6)) // []
  • 1
  • 2
  • 3
  • 4

源码实现

// 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()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

dropLast

drop 刚好相反,dropLast 是从尾部过滤。n < 0 时抛出 IllegalArgumentException 异常,n = 0 时返回原集合,n >= 集合长度时返回空集合

val heroName = listOf("蛮三刀", "托儿索", "儿童劫", "提款姬", "菊花信")
println(heroName.dropLast(0))  // [蛮三刀, 托儿索, 儿童劫, 提款姬, 菊花信]
println(heroName.dropLast(2))  // [蛮三刀, 托儿索, 儿童劫]
println(heroName.dropLast(6))  // []
  • 1
  • 2
  • 3
  • 4

源码实现

// 通过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))
}
  • 1
  • 2
  • 3
  • 4
  • 5

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]
  • 1
  • 2
  • 3

源码实现

// 通过迭代器从后到前迭代,直到不满足条件时通过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()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

dropWhile

根据条件从头部开始过滤元素,与 dropLastWhile 刚好相反,直到某个元素不满足条件时返回剩余集合

还是上面的例子,不过我们调整下筛选的规则,公司需要后来先到的原则并且男士(或女士)优先的原则,舍弃掉头部的求职者

val names = listOf("陈女士", "张先生", "王先生", "蔡女士", "李先生", "钟女士", "朱先生")
println(names.dropWhile { it.endsWith("女士") }) // [张先生, 王先生, 蔡女士, 李先生, 钟女士, 朱先生]
println(names.dropWhile { it.endsWith("先生") }) // [陈女士, 张先生, 王先生, 蔡女士, 李先生, 钟女士, 朱先生]
  • 1
  • 2
  • 3

源码实现

// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

elementAt

返回索引下的元素,当索引不在有效范围内[0, lastIndex] 抛出数组越界异常,可以使用 elementAtOrNullelementAtOrElse 代替

val mobileGames = listOf("和平精英", "英雄联盟手游", "欢乐斗地主")
println(mobileGames.elementAt(1)) // 英雄联盟手游
println(mobileGames.elementAt(mobileGames.lastIndex + 1)) // java.lang.ArrayIndexOutOfBoundsException 异常
  • 1
  • 2
  • 3

源码实现

// 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.") }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

elementAtOrElse

返回索引下的元素,当索引不在有效范围内[0, lastIndex] 时返回默认值

val mobileGames = listOf("和平精英", "英雄联盟手游", "欢乐斗地主")
println(mobileGames.elementAtOrElse(1) { "未找到游戏" }) // 英雄联盟手游
println(mobileGames.elementAtOrElse(mobileGames.lastIndex + 1) { "未找到游戏" }) // 未找到游戏
  • 1
  • 2
  • 3

源码实现

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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

elementAtOrNull

返回索引下的元素,当索引不在有效范围内[0, lastIndex] 时返回null

例如

val list = listOf(1, 2, 3, 4, 5)
list.elementAtOrNull(3) = 4
list.elementAtOrNull(5) = null
  • 1
  • 2
  • 3

源码实现

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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

filter

按条件过滤元素,返回满足条件的所有元素

例如

val names = listOf("司马懿", "诸葛亮", "吕布", "黄忠", "赵云", "凤雏庞统")
println(names.filter { it.length >= 3 })
  • 1
  • 2

源码实现

// 通过filterTo实现,filterTo后面再说
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}
  • 1
  • 2
  • 3
  • 4

filterIndexed

按条件过滤元素,与 filter 不同的是 filterIndexed 的函数类型的参数会多一个 int 类型的 index 索引

例如我们以单双划分集合

val names = listOf("司马懿", "诸葛亮", "吕布", "黄忠", "赵云", "凤雏庞统")
val even = names.filterIndexed { index, _ -> index % 2 == 0 } // [司马懿, 吕布, 赵云] 
val odd =  names.filterIndexed { index, _ -> index % 2 == 1 } // [诸葛亮, 黄忠, 凤雏庞统]
  • 1
  • 2
  • 3

源码实现

// 通过filterIndexedTo实现,传进去的集合是ArrayList
public inline fun <T> Iterable<T>.filterIndexed(predicate: (index: Int, T) -> Boolean): List<T> {
    return filterIndexedTo(ArrayList<T>(), predicate)
}
  • 1
  • 2
  • 3
  • 4

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 } // [吕布, 诸葛亮, 赵云]
  • 1
  • 2
  • 3
  • 4
  • 5

源码实现

// 传进来的集合必须是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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

filterIsInstance

过滤同类型的元素,返回新的集合

例如我们有如下集合,我们需要以 StringInt 划分

val typeValues =  listOf("蔡徐坤", 88, "唱跳rap", "篮球", 177, 68)
println(typeValues.filterIsInstance<String>()) // [蔡徐坤, 唱跳rap, 篮球]
println(typeValues.filterIsInstance<Int>()) // [88, 177, 68]
  • 1
  • 2
  • 3

源码实现

// 通过filterIsInstanceTo实现,参数是ArrayList
public inline fun <reified R> Iterable<*>.filterIsInstance(): List<@kotlin.internal.NoInfer R> {
    return filterIsInstanceTo(ArrayList<R>())
}
  • 1
  • 2
  • 3
  • 4

filterIsInstanceTo

过滤同类型的元素,将过滤后的元素添加到集合中

val stringSet = hashSetOf<String>()
val intSets = hashSetOf<Int>()
val typeValues = listOf("蔡徐坤", 88, "唱跳rap", "篮球", 177, 68)
println(typeValues.filterIsInstanceTo(stringSet))
println(typeValues.filterIsInstanceTo(intSets))
  • 1
  • 2
  • 3
  • 4
  • 5

源码实现

// 通过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
}
  • 1
  • 2
  • 3
  • 4
  • 5

filterNot

按条件过滤元素,返回不满足条件的所有元素,刚好与 filter 相反

例如我们需要获取大学名字长度不等于4的大学

val universitySet =
    setOf("厦门大学", "四川大学", "清华大学", "中山大学", "武汉理工大学", "华南理工大学", "中国传媒大学")
println(universitySet.filterNot { it.length == 4 }) // [武汉理工大学, 华南理工大学, 中国传媒大学]
  • 1
  • 2
  • 3

源码实现

// 通过filterNotTo过滤
public inline fun <T> Iterable<T>.filterNot(predicate: (T) -> Boolean): List<T> {
    return filterNotTo(ArrayList<T>(), predicate)
}
  • 1
  • 2
  • 3
  • 4

filterNotNull

过滤掉 null 的元素

val random = listOf<Any?>("蔡徐坤", 2.5f, "唱跳rap", null)
println(random.filterNotNull()) //[蔡徐坤, 2.5, 唱跳rap]
  • 1
  • 2

源码实现

// 通过filterNotNullTo过滤
public fun <T : Any> Iterable<T?>.filterNotNull(): List<T> {
    return filterNotNullTo(ArrayList<T>())
}
  • 1
  • 2
  • 3
  • 4

filterNotNullTo

过滤掉 null 的元素,将剩余的元素添加到传进来的集合中

val random = listOf<Any?>("蔡徐坤", 2.5f, "唱跳rap", null)
val hashSet = hashSetOf<Any>() 
println(random.filterNotNullTo(hashSet)) // [2.5, 唱跳rap, 蔡徐坤]
  • 1
  • 2
  • 3

源码实现

// 如果元素为空,则添加到传进来的集合中
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
}
  • 1
  • 2
  • 3
  • 4
  • 5

filterNotTo

按条件过滤元素,将不满足条件的元素添加到传进来的集合中

例如

val universitySet =
    setOf("厦门大学", "四川大学", "清华大学", "中山大学", "武汉理工大学", "华南理工大学", "中国传媒大学")
val lenNot4Items = hashSetOf<String>()
println(universitySet.filterNotTo(lenNot4Items) { it.length == 4 }) // [武汉理工大学, 华南理工大学, 中国传媒大学]
  • 1
  • 2
  • 3
  • 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
}
  • 1
  • 2
  • 3
  • 4
  • 5

filterTo

按条件过滤元素,将满足条件的元素添加到传进来的集合中, 刚好与 filterNotTo 相反

例如

@Test
fun filterToExample() {
    val universitySet =
        setOf("厦门大学", "四川大学", "清华大学", "中山大学", "武汉理工大学", "华南理工大学", "中国传媒大学")
    val len4Items = hashSetOf<String>()
    println(universitySet.filterTo(len4Items) { it.length == 4 }) // [厦门大学, 四川大学, 中山大学, 清华大学]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

源码实现

// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5

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
  • 1
  • 2
  • 3

源码实现

// 内部通过firstOrNull实现
public inline fun <T> Iterable<T>.find(predicate: (T) -> Boolean): T? {
    return firstOrNull(predicate)
}
  • 1
  • 2
  • 3
  • 4

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
  • 1
  • 2
  • 3

源码实现

// 内部通过lastOrNull实现
public inline fun <T> List<T>.findLast(predicate: (T) -> Boolean): T? {
    return lastOrNull(predicate)
}
  • 1
  • 2
  • 3
  • 4

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.
  • 1
  • 2
  • 3
  • 4

源码实现

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()
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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.
  • 1
  • 2
  • 3
  • 4

源码实现

// 将转换函数传递给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.")
}
  • 1
  • 2
  • 3
  • 4

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 获取转换之后的值,如果不是空就返回
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 对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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

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]
  • 1
  • 2
  • 3
  • 4

源码实现

// flatMapTo到ArrayList
public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
    return flatMapTo(ArrayList<R>(), transform)
}
  • 1
  • 2
  • 3
  • 4

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) })
  • 1
  • 2

源码实现

// flatMapIndexedTo到ArrayList
public inline fun <T, R> Iterable<T>.flatMapIndexed(transform: (index: Int, T) -> Iterable<R>): List<R> {
    return flatMapIndexedTo(ArrayList<R>(), transform)
}
  • 1
  • 2
  • 3
  • 4

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]
  • 1
  • 2
  • 3
  • 4

源码实现

// 遍历整个集合,将转换函数获得的集合添加到传进来的集合中
// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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)
  • 1
  • 2
  • 3
  • 4

源码实现

// 遍历整个集合,将转换函数获得的集合添加到传进来的集合中
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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
  • 1
  • 2
  • 3

源码实现

// 遍历整个集合,将上一个的结果传到下一个的遍历中,需要传入初始值
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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 })
  • 1
  • 2
  • 3

源码实现

// 遍历整个集合,将上一个的结果传到下一个的遍历中,需要传入初始值
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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
  • 1
  • 2
  • 3

源码实现

// 通过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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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
  • 1
  • 2
  • 3

源码实现

// // 通过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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

forEach

forEach 遍历,lambda 返回每一个元素

val intList = listOf(1, 2, 3, 4, 5)
intList.forEach {
    println(it)
}
// 1 2 3 4 5
  • 1
  • 2
  • 3
  • 4
  • 5

源码实现

// for循环遍历
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
    for (element in this) action(element)
}
  • 1
  • 2
  • 3
  • 4

关于 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)
}
  • 1
  • 2
  • 3
  • 4
  • 5

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 没有数组越界通过 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)
}
  • 1
  • 2
  • 3
  • 4

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
  • 1
  • 2
  • 3

源码实现

// 没有数组越界通过 get方法获取,数组越界返回null
public fun <T> List<T>.getOrNull(index: Int): T? {
    return if (index >= 0 && index <= lastIndex) get(index) else null
}
  • 1
  • 2
  • 3
  • 4

groupBy

根据分组函数对集合进行分组,返回分组结果 MapMap 中的 key 类型由分组函数决定, value 的类型是 List

groupBy 两个参数的函数会对集合元素的值进行转换,最终添加到 Map

例如我们需要对字符串按长度进行分组,那么 Mapkey 就是 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_]}
  • 1
  • 2
  • 3
  • 4

源码实现

// 通过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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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_]}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

源码实现

// 根据分组函数获取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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

indexOf

获取元素的索引,当不存在该元素时返回 -1,如果只是判断是否在集合中 优先采用 contains

val kingdoms = setOf("秦", "楚", "齐", "燕", "赵", "魏", "韩")
println(kingdoms.indexOf("齐")) // 2
println(kingdoms.indexOf("唐")) // -1
  • 1
  • 2
  • 3

源码实现

// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

indexOfFirst

获取第一个满足条件的元素的索引,当所有元素都不满足条件时返回 -1

val typeValues = listOf("蔡徐坤", 88, "唱跳rap", "篮球", 177, 68)
println(typeValues.indexOfFirst { it == "唱跳rap" }) // 2
println(typeValues.indexOfFirst { it == "两年半" })  // -1
  • 1
  • 2
  • 3

源码实现

// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

indexOfLast

获取最后一个满足条件的元素的索引,当所有元素都不满足条件时返回 -1

val typeValues = listOf("蔡徐坤", 88, "唱跳rap", "篮球", 177, "唱跳rap", 68)
println(typeValues.indexOfLast { it == "唱跳rap" }) // 5
println(typeValues.indexOfLast { it == "两年半" })  // -1
  • 1
  • 2
  • 3

源码实现

// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

intersect

获取两个集合中交集,返回的是 set

val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
val finalFourBy2022 = listOf("凯尔特人", "勇士", "热火", "独行侠")
println(finalFourBy2023.intersect(finalFourBy2022)) // [凯尔特人, 热火]
  • 1
  • 2
  • 3

源码实现

// 通过retainAll获取交集
public infix fun <T> Iterable<T>.intersect(other: Iterable<T>): Set<T> {
    val set = this.toMutableSet()
    set.retainAll(other)
    return set
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

joinTo

将所有的元素连接到一起,通过前缀、后缀和分隔符连接。一般我们都是使用 StringBuilder 进行格式化输出,用得更多的是 joinToString

val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
val sb = StringBuilder()
println(finalFourBy2023.joinTo(sb, separator = "#", prefix = "{", postfix = "}")) // {凯尔特人#热火#湖人#掘金}
  • 1
  • 2
  • 3

源码实现

// 通过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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

joinToStrin

格式化输出集合中的所有元素,返回字符串

val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
println(finalFourBy2023.joinToString(separator = "#", prefix = "{", postfix = "}")) // {凯尔特人#热火#湖人#掘金}
  • 1
  • 2

源码实现

// 通过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()
}
  • 1
  • 2
  • 3
  • 4

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 通过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]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

lastIndexOf

获取某个元素在集合中最后一个元素的索引,当不存在该元素时返回-1。indexOf 是获取第一个出现该元素的索引 ,lastIndexOfindexOf 刚好相反

val typeValues = listOf("蔡徐坤", 88, "唱跳rap", "篮球", 177, "唱跳rap", 68)
println(typeValues.lastIndexOf("唱跳rap")) // 5
println(typeValues.lastIndexOf("两年半"))  // -1
  • 1
  • 2
  • 3

源码实现

// 对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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 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
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

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]]
  • 1
  • 2
  • 3
  • 4

可以很明显看到 mapflatMap 的区别,flatMap 会铺平整个集合,而 map 只是将转换元素累计

源码实现

// 调用mapTo实现,传入转换函数和ArrayList
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
  • 1
  • 2
  • 3
  • 4

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]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

源码实现

// 调用mapIndexedTo实现,传入转换函数和ArrayList
public inline fun <T, R> Iterable<T>.mapIndexed(transform: (index: Int, T) -> R): List<R> {
    return mapIndexedTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
  • 1
  • 2
  • 3
  • 4

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,所以不输出
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

源码实现

// 通过mapIndexedNotNullTo
public inline fun <T, R : Any> Iterable<T>.mapIndexedNotNull(transform: (index: Int, T) -> R?): List<R> {
    return mapIndexedNotNullTo(ArrayList<R>(), transform)
}
  • 1
  • 2
  • 3
  • 4

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]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

源码实现

// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5

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]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

源码实现

// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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]
  • 1
  • 2

源码实现

// 调用mapNotNullTo实现,传入转换函数
public inline fun <T, R : Any> Iterable<T>.mapNotNull(transform: (T) -> R?): List<R> {
    return mapNotNullTo(ArrayList<R>(), transform)
}
  • 1
  • 2
  • 3
  • 4

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]
  • 1
  • 2
  • 3

源码实现

// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5

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 } })
  • 1
  • 2
  • 3
  • 4

源码实现

// 转换函数进行转换后添加到集合,会修改传进来的集合参数
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

minus

获取两个集合中的差值,或者集合中去除某个元素,返回 List

val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
val finalFourBy2022 = listOf("凯尔特人", "勇士", "热火", "独行侠")
println(finalFourBy2023.minus(finalFourBy2022)) // [湖人, 掘金]
println(finalFourBy2023 - finalFourBy2022) // 跟上面的表述是一样的,因为minus是一个操作符operator
println(finalFourBy2023.minus("热火")) // [凯尔特人, 湖人, 掘金]
println(finalFourBy2023 - "热火")      // 跟上面的表述是一样的,因为minus是一个操作符operator
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

源码实现

// 实际是通过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 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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
  • 1
  • 2
  • 3

源码实现

// 集合为空就返回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()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

onEach

遍历整个集合,与 forEach 不同的是,onEach 返回集合本身,所以我们使用 onEach 之后可以继续调用链式调用集合操作符

val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
company.onEach { println(it) } // 输出整个集合
    .filter { it.length > 5 }  // 过滤元素
  • 1
  • 2
  • 3

源码实现

// 通过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) }
}
  • 1
  • 2
  • 3
  • 4

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 } // // 过滤元素
  • 1
  • 2
  • 3

源码实现

// forEachIndexed遍历
public inline fun <T, C : Iterable<T>> C.onEachIndexed(action: (index: Int, T) -> Unit): C {
    return apply { forEachIndexed(action) }
}
  • 1
  • 2
  • 3
  • 4

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)"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

例如我们需要将小伙伴根据性别进行分类,非男即女嘛

val names = listOf("陈女士", "张先生", "王先生", "蔡女士", "李先生", "钟女士", "朱先生")
val pair = names.partition { it.endsWith("先生") }
println(pair.first) // [张先生, 王先生, 李先生, 朱先生]
println(pair.second) // [陈女士, 蔡女士, 钟女士]
  • 1
  • 2
  • 3
  • 4

源码实现

// 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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

源码实现

// 如果是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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

plusElement

添加某个元素到集合中,不是操作符,所以不能使用 “+”,其内部也是通过 plus 实现

源码实现

public inline fun <T> Iterable<T>.plusElement(element: T): List<T> {
    return plus(element)
}
  • 1
  • 2
  • 3

randomrandomOrNull

随机获取某个元素,与我们常用的 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))
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 通过迭代器迭代集合,如果为空则抛出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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 通过迭代器迭代集合,如果为空则抛出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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 通过迭代器迭代集合,如果为空则返回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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 集合为空则返回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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 使用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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 使用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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 使用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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 使用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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 很简单,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>
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

reversed

反序集合,返回 List

val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
println(finalFourBy2023.reversed())  // [掘金, 湖人, 热火, 凯尔特人]
  • 1
  • 2

源码实现

// 长度小于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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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]
  • 1
  • 2
  • 3

源码实现

// 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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]
  • 1
  • 2
  • 3

源码实现

// 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

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]
  • 1
  • 2
  • 3
  • 4

源码实现

// 空集合则直接返回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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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]
  • 1
  • 2
  • 3
  • 4

源码实现

// 空集合则直接返回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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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)
}
  • 1
  • 2
  • 3

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)
}
  • 1
  • 2
  • 3

shuffle

打乱集合的顺序,随机排列集合元素。

val finalFourBy2023 = setOf("凯尔特人", "热火", "湖人", "掘金")
println(finalFourBy2023.shuffled()) // [湖人, 掘金, 凯尔特人, 热火],每一个都有可能是新的一次排序,这里只是随机了其中一次
  • 1
  • 2

源码实现

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

当然,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])
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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
  • 1
  • 2
  • 3
  • 4

源码实现

// 通过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
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

singleOrNull

判断集合中有且只有一个元素满足条件,如果有多个元素满足条件或者没有元素满足条件则返回 null

val finalFourBy2023 = setOf("凯尔特人", "热火", "湖人", "掘金")
println(finalFourBy2023.singleOrNull { it.length > 2 })  // 凯尔特人
println(finalFourBy2023.singleOrNull { it.endsWith("人") }) // null
println(finalFourBy2023.singleOrNull { it == "太阳" }) // null
  • 1
  • 2
  • 3
  • 4

源码实现

// 与 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
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

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)))  // [陈女士, 张先生, 王先生]
  • 1
  • 2
  • 3
  • 4

或者我们需要随机获取集合,可以这样做

val names = listOf("陈女士", "张先生", "王先生", "蔡女士", "李先生", "钟女士", "朱先生")
println(names.slice(listOf(0, 5, 4, 3)))  // [陈女士, 钟女士, 李先生, 蔡女士]
println(names.slice(listOf(0, 5, 7, 3, 9))) // java.lang.ArrayIndexOutOfBoundsException
  • 1
  • 2
  • 3

注意 不管是 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

sortBy

根据函数类型参数的返回值进行排序集合,其实是通过 ASCII 值排序。会修改原集合,返回的是 Unit,只作用于 MutableListMutableListList 的区别?MutableList 可以 curdList 只能获取和遍历

例如根据姓名或者年龄排序

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)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

源码实现

// 通过sortWith排序
public inline fun <T, R : Comparable<R>> MutableList<T>.sortBy(crossinline selector: (T) -> R?): Unit {
    if (size > 1) sortWith(compareBy(selector))
}
  • 1
  • 2
  • 3
  • 4

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)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

源码实现

// 通过sortWith排序
public inline fun <T, R : Comparable<R>> MutableList<T>.sortByDescending(crossinline selector: (T) -> R?): Unit {
    if (size > 1) sortWith(compareByDescending(selector))
}
  • 1
  • 2
  • 3
  • 4

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)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

源码实现

// sortWith,传入reverseOrder,我们可以大胆猜测就是reverseOrder是的排序降序的
public fun <T : Comparable<T>> MutableList<T>.sortDescending(): Unit {
    sortWith(reverseOrder())
}
  • 1
  • 2
  • 3
  • 4

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)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

源码实现

// 如果是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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

源码实现

// sortedWith实现
public inline fun <T, R : Comparable<R>> Iterable<T>.sortedBy(crossinline selector: (T) -> R?): List<T> {
    return sortedWith(compareBy(selector))
}
  • 1
  • 2
  • 3
  • 4

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)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

源码实现

public inline fun <T, R : Comparable<R>> Iterable<T>.sortedBy(crossinline selector: (T) -> R?): List<T> {
    return sortedWith(compareBy(selector))
}
  • 1
  • 2
  • 3

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)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

源码实现

// reverseOrder 降序
public fun <T : Comparable<T>> Iterable<T>.sortedDescending(): List<T> {
    return sortedWith(reverseOrder())
}
  • 1
  • 2
  • 3
  • 4

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)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

源码实现

// 如果是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) }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

好累好累~,终于讲完了排序,排序的知识还是蛮多的。插一句话,一般情况下都是 sortByxxx 会多点,它会修改原集合的顺序,而如果你需要返回一个新的集合,则考虑使用 sortedxxx

subtract

返回集合中包含而指定集合中不包含的所有元素(差集),返回的是 set。从结果上好像和 minus 是一样的,不同的是 minus 返回的是 List

val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
val finalFourBy2022 = listOf("凯尔特人", "勇士", "热火", "独行侠")
println(finalFourBy2023.subtract(finalFourBy2022)) // [湖人, 掘金] 
println(finalFourBy2023.minus(finalFourBy2022))  // [湖人, 掘金]
  • 1
  • 2
  • 3
  • 4

源码实现

// toMutableSet移除removeAll
public infix fun <T> Iterable<T>.subtract(other: Iterable<T>): Set<T> {
    val set = this.toMutableSet()
    set.removeAll(other)
    return set
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

sum

返回集合中的所有元素的总和,因为是累加的所以只作用于 ByteDoubleFloatIntLongShort 基本类型集合。

这个就不多说了,相信大家都知道是怎么实现的吧。没错,就是常规的 for 循环遍历罢了

随便看下其中一个的源码

public fun Iterable<Byte>.sum(): Int {
    var sum: Int = 0
    for (element in this) {
        sum += element
    }
    return sum
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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
  • 1
  • 2

随便看下其中一个的源码

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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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))  // [陈女士, 张先生, 王先生, 蔡女士, 李先生, 钟女士, 朱先生]
  • 1
  • 2
  • 3
  • 4
  • 5

源码实现

// 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()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

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)) // [陈女士, 张先生, 王先生, 蔡女士, 李先生, 钟女士, 朱先生]
  • 1
  • 2
  • 3
  • 4
  • 5

源码实现

// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

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]
  • 1
  • 2
  • 3
  • 4

源码实现

// 通过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()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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]
  • 1
  • 2
  • 3
  • 4

源码实现

// 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

toxxxArray

将xx集合转换成xx数组,主要有 toBooleanArraytoByteArraytoCharArraytoDoubleArraytoFloatArraytoIntArraytoLongArray

下面就以 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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

源码实现

// 很简单的for循环,就是创建一个BooleanArray长度为集合长度
public fun Collection<Boolean>.toBooleanArray(): BooleanArray {
    val result = BooleanArray(size)
    var index = 0
    for (element in this)
        result[index++] = element
    return result
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

toxxx

将集合转换为特定的集合,例如 toCollection 转换成 MutableCollectiontoList 转换成 List。常用的方法有 toListtoMutableListtoMutableSettoSet

这个就不举例了,相信大家都会使用和看得懂源码

union

获取两个集合的交集,返回 Set

val finalFourBy2023 = listOf("凯尔特人", "热火", "湖人", "掘金")
val finalFourBy2022 = listOf("凯尔特人", "勇士", "热火", "独行侠")
println(finalFourBy2023.union(finalFourBy2022)) // [凯尔特人, 热火, 湖人, 掘金, 勇士, 独行侠]
  • 1
  • 2
  • 3

源码实现

// 通过toMutableSet去添加另一个集合
public infix fun <T> Iterable<T>.union(other: Iterable<T>): Set<T> {
    val set = this.toMutableSet()
    set.addAll(other)
    return set
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

windowed

获取集合中从左到右所有给定长度的子集的集合,返回 List<List>。 可以设置子集的长度 size;每一个子集之间的间距 step 默认是 1; partialWindows 可以控制末尾的子集的长度是否可以小于 size,默认是 falsetransform 是用于转换的,需要转换子集的话可以用上这个。sizestep 都必须大于 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]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

源码实现

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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

zip

获取两个集合中相同索引的元素对,为什么我称它为元素对,因为它是从一个集合中取出元素,又从另一个集合中取出该元素的索引的元素,在 KotlinPair 形容这个元素对。所以返回值是 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]
  • 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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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" }) // [掘金 -> 热火, 热火 -> 凯尔特人, 凯尔特人 -> 湖人]
  • 1
  • 2
  • 3
  • 4
  • 5

源码实现

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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

总结

终于把集合操作符都讲完了,大概是用了5天的时间吧,把所有的操作符从头到尾的讲了一遍,特别是源码方面的东西,我个人还是第一次这么深层次的去看 Kotlin 的源码实现。怎么说呢,学习源码对自己的提升肯定是有的,特别是对算法效率提升方面的提升。我工作了五年,也是第一次写这么一篇长篇大论,感觉还是挺累的,不过累并快乐着~。接下来有计划把字符串或者 Map 的操作符也一并干碎,如果喜欢的话可以给个点赞哈,当然文中可能还有一些不足的地方,欢迎小伙伴在底下留言评论 华山论剑

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/575928
推荐阅读
相关标签
  

闽ICP备14008679号