IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Kotlin集合全解析 -> 正文阅读

[移动开发]Kotlin集合全解析

集合概念

Kotlin 100%与Java互操作,所以Java中集合在Kotlin同样可以使用,如大家熟悉的ArrayList、HashMap、Set等。

Kotlin中三种基本的容器分别为Set、Map、List。

三种容器有一些共同的方法:

  • isEmpty 判定容器是否为空
  • isNotEmpty 判断容器是否非空
  • clear 清空容器
  • contains 是否包含指定元素

集合类型

每种容器又分为只读与可变两者类型,只读没有add、remove等操作方法,可变类型具有这些操作方法,这在概念上就将读写进行了分离。

  • 一个 只读 接口,提供访问集合元素的操作。
  • 一个 可变 接口,通过写操作扩展相应的只读接口:添加、删除及更新其元素。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oH3IiSsO-1664162428764)(http://192.168.120.239:4999/server/index.php?s=/api/attachment/visitFile/sign/f288c8f776d830bfec66de626c752837 “集合的类继承关系图”)]

Collection<T> 是集合层次结构的根,表示只读集合的共同行为:检索大小、 检测是否为成员等等。 Collection 继承自 Iterable <T> 接口,它定义了迭代元素的操作。可以使用 Collection 作为适用于不同集合类型的函数的参数。
MutableCollection<T> 是一个具有写操作的 Collection 接口,例如 add 以及 remove

List

  • 按顺序存储元素,通过索引读取元素。
  • 只读类型List<T>,可变类型MutableList<T>
  • 同数组(Array)类似,但是Array初始化定义,不会变,List没有预设大小,可通过Add、remove等方法更新。
  • 默认实现ArrayList。
  • List可包含空值,可重复,可相等。

Set

  • 存储顺序不按顺序。
  • 只读类型Set<T>,可变类型MutableSet
  • 一个 Set 只能包含一个 null。
  • 大小和元素都相同时候则相等。

Map

  • 存储键值对,不是 Collection 接口的继承者。
  • 只读类型Map<K, V>,可变类型MutableMap
  • 键是唯一的,但是不同的键可以与相同的值配对。
  • Map 接口提供特定的函数进行通过键访问值、搜索键和值等操作。
  • 大小和键值完全相同的两个Map相等。
  • 默认实现LinkedHashMap,保证顺序,HashMap不保证顺序。

初始化方法

使用库函数初始化

使用listOfmutableListOf函数初始化,其中listOf创建的是只读集合,mutableListOf创建的是可变集合。

//创建只读列表
val numbers = listOf("one", "two", "three", "four")
//创建可变列表
val mutableNumbers = mutableListOf("one", "two", "three", "four")

setmap初始化与上面类似。
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)
考虑map性能时候使用如下写法
val numbersMap = mutableMapOf<String, String>().apply { this["one"] = "1"; this["two"] = "2" }

使用构造器函数初始化

使用下列形式的构造函数 buildList(), buildSet(), 或者 buildMap()
示例代码:

val map = buildMap { // this is MutableMap<String, Int>, types of key and value are inferred from the `put()` calls below
    put("a", 1)
    put("b", 0)
    put("c", 4)
}

println(map) // {a=1, b=0, c=4}

空集合

没有任何元素的集合emptyList()emptySet()emptyMap()

List初始化

传入大小及初始化函数

val doubled = List(3, { it * 2 })  // 如果你想操作这个集合,应使用 MutableList
println(doubled)

具体类型构造函数

针对ArrayListLinkedListHashMap的初始化

val linkedList = LinkedList<String>(listOf("one", "two", "three"))
val presizedSet = HashSet<Int>(32)

复制初始化

-使用复制函数创建一个新的集合,例如toList() toMutableList()toSet()等等

   val alice = Person("Alice")
    val sourceList = mutableListOf(alice, Person("Bob"))
    val copyList = sourceList.toList()
    sourceList.add(Person("Charles"))

-不同类型之间的转换

val sourceList = mutableListOf(1, 2, 3)
val copySet = sourceList.toMutableSet()

-创建对同一集合实例的新引用

val sourceList = mutableListOf(1, 2, 3)
    val referenceList = sourceList

调用其他集合的函数

可以通过其他集合各种操作的结果来创建集合。
例如调用filter函数创建新的集合

val numbers = listOf("one", "two", "three", "four")
    val longerThan3 = numbers.filter { it.length > 3 }

迭代器

用于遍历集合,同Java的迭代器概念一致。

val numbers = listOf("one", "two", "three", "four")
    val numbersIterator = numbers.iterator()
    while (numbersIterator.hasNext()) {
        println(numbersIterator.next())
    }

使用for遍历

val numbers = listOf("one", "two", "three", "four")
    for (item in numbers) {
        println(item)
    }

使用forEach遍历

val numbers = listOf("one", "two", "three", "four")
    numbers.forEach {
        println(it)
    }

List迭代器

对于列表,有一个特殊的迭代器实现: ListIterator。 它支持列表双向迭代:正向与反向。反向迭代由 hasPrevious()previous() 函数实现。通过 nextIndex()previousIndex() 函数提供有关元素索引的信息

val numbers = listOf("one", "two", "three", "four")
    val listIterator = numbers.listIterator()
    while (listIterator.hasNext()) listIterator.next()
    println("Iterating backwards:")
    while (listIterator.hasPrevious()) {
        print("Index: ${listIterator.previousIndex()}")
        println(", value: ${listIterator.previous()}")
    }

可变迭代器

为了迭代可变集合,于是有了 MutableIterator 来扩展 Iterator 使其具有元素删除函数 remove() ,也可插入与替换。

val numbers = mutableListOf("one", "two", "three", "four") 
    val mutableIterator = numbers.iterator()
    mutableIterator.next()
    mutableIterator.remove()
    mutableListIterator.add("two")
    mutableListIterator.next()
    mutableListIterator.set("three")
    println("After removal: $numbers")

区间与数列

Kotlin中区间使用 rangeTo() 函数及其操作符形式的 ..来表示。通常,rangeTo() 会辅以 in!in 函数。
区间使用示例:
用于条件判定

val i = 1
//sampleStart
    if (i in 1..4) { // 等同于 1 <= i && i <= 4
        print(i)
    }

用于遍历

for (i in 1..4) print(i)

反向迭代
反向迭代数字,请使用 downTo

for (i in 4 downTo 1) print(i)

也可以通过任意步长(不一定为 1 )迭代数字,使用step函数

for (i in 1..8 step 2) print(i)
    println()
    for (i in 8 downTo 1 step 2) print(i)

不包含其结束元素的数字区间,使用until

 for (i in 1 until 10) {       // i in 1 到 10, 不含 10
        print(i)
    }

区间

定义:有端点的封闭的间隔,为比较类型定义,有顺序。
举个版本号比较的例子

class Version(val major: Int, val minor: Int): Comparable<Version> {
    override fun compareTo(other: Version): Int {
        if (this.major != other.major) {
            return this.major - other.major
        }
        return this.minor - other.minor
    }
}

//使用
val versionRange = Version(1, 11)..Version(1, 30)
    println(Version(0, 9) in versionRange)
    println(Version(1, 20) in versionRange)

数列

整数区间的等差数列,包含类型IntLongChar。在 Kotlin 中,这些数列由特殊类型定义:IntProgression LongProgressionCharProgression
数列具有三个基本属性:first 元素、last 元素和一个非零的 step。

for (int i = first; i <= last; i += step) {
  // ……
}

step为1
for (i in 1..10) print(i)

step为其他值

for (i in 1..8 step 2) print(i)

数列的 last 元素是这样计算的:

  • 对于正步长:不大于结束值且满足 (last - first) % step == 0 的最大值。
  • 对于负步长:不小于结束值且满足 (last - first) % step == 0 的最小值。
    因此,last 元素并非总与指定的结束值相同。
for (i in 1..9 step 3) print(i) // 最后一个元素是 7

反向数列使用downTo

for (i in 4 downTo 1) print(i)

也可使用取反函数

for (i in (1..4).reversed()) print(i)

数列也实现了迭代器接口Iterable<N>,其中 N 分别是 Int、Long 或 Char,各种集合函数,例如mapfilter等也使用于数列。

println((1..10).filter { it % 2 == 0 })

序列

序列(Sequence<T>)提供与 Iterable 相同的函数。
区别:

  • Iterable按顺序执行每个函数,然后生成中间结果传递给下个函数,Sequence有点懒执行的味道,仅当整个处理链的结果时才进行实际计算。
  • Sequence 对每个元素逐个执行所有处理步骤;Iterable 完成整个集合的每个步骤,然后进行下一步。
  • Sequence避免生成中间结果,提升性能, 但是其惰性性质增加了一些开销,这些开销在处理较小的集合或进行更简单的计算时可能很重要。
    总结

少量数据使用Iterable,大量数据使用Sequence

构造

由元素

val numbersSequence = sequenceOf("four", "three", "two", "one")

由 Iterable

val numbers = listOf("one", "two", "three", "four")
val numbersSequence = numbers.asSequence()

由函数

val oddNumbers = generateSequence(1) { it + 2 } // `it` 是上一个元素
    println(oddNumbers.take(5).toList())
    //println(oddNumbers.count())     // 错误:此序列是无限的。

创建有限序列

//最后一个元素之后返回null
val oddNumbersLessThan10 = generateSequence(1) { if (it < 8) it + 2 else null }
    println(oddNumbersLessThan10.count())

由块函数
sequence() 函数。 此函数采用一个 lambda 表达式,其中包含 yield()yieldAll()函数的调用。 它们将一个元素返回给序列使用者,并暂停 sequence() 的执行,直到使用者请求下一个元素。 yield() 使用单个元素作为参数;yieldAll() 中可以采用 Iterable 对象、 Iterator 或其他 SequenceyieldAll()Sequence 参数可以是无限的。 当然,这样的调用必须是最后一个: 之后的所有调用都永远不会执行。

 val oddNumbers = sequence {
        yield(1)
        yieldAll(listOf(3, 5))
        yieldAll(generateSequence(7) { it + 2 })
    }
    println(oddNumbers.take(5).toList())

序列操作

分类如下:

  • 无状态 操作不需要状态,并且可以独立处理每个元素,例如 map()filter()。 无状态操作还可能需要少量常数个状态来处理元素,例如 take()drop()
  • 有状态 操作需要大量状态,通常与序列中元素的数量成比例。

如果序列操作返回延迟生成的另一个序列,则称为 中间序列。 否则,该操作为 末端操作。 末端操作的示例为 toList()sum()只能通过末端操作才能检索序列元素
序列可以多次迭代;但是,某些序列实现可能会约束自己仅迭代一次。

序列与迭代器直观比较

下面举个过滤单词的例子看 Iterable 与 Sequence 之间的区别
假定有一个单词列表。下面的代码过滤长于三个字符的单词,并输出前四个单词的长度。
Iterable
代码示例

 val words = "The quick brown fox jumps over the lazy dog".split(" ")
    val lengthsList = words.filter { println("filter: $it"); it.length > 3 }
        .map { println("length: ${it.length}"); it.length }
        .take(4)

    println("Lengths of first 4 words longer than 3 chars:")
    println(lengthsList)

处理流程图
在这里插入图片描述

Sequence
代码示例

val words = "The quick brown fox jumps over the lazy dog".split(" ")
    // 将列表转换为序列
    val wordsSequence = words.asSequence()

    val lengthsSequence = wordsSequence.filter { println("filter: $it"); it.length > 3 }
        .map { println("length: ${it.length}"); it.length }
        .take(4)

    println("Lengths of first 4 words longer than 3 chars")
    // 末端操作:以列表形式获取结果。
    println(lengthsSequence.toList())

处理流程图
在这里插入图片描述

在此示例中,序列处理需要 18 个步骤,而不是 23 个步骤来执行列表操作。

集合操作

集合操作包括简单的获取、添加、删除,复杂的过滤、搜索、排序、分组、转换。

集合操作在标准库中以两种方式声明:集合接口的成员函数扩展函数
成员函数如isEmpty(),get()
扩展函数如filtersortgroupBy

公共操作可用于只读集合与可变集合。 公共操作分为以下几类:

  • 集合转换
  • 集合过滤
  • plus 与 minus 操作符
  • 分组
  • 取集合的一部分
  • 取单个元素
  • 集合排序
  • 集合聚合操作

这些页面中描述的操作将返回其结果,而不会影响原始集合

val numbers = listOf("one", "two", "three", "four")  
    numbers.filter { it.length > 3 }  // `numbers` 没有任何改变,结果丢失
    println("numbers are still $numbers")
    val longerThan3 = numbers.filter { it.length > 3 } // 结果存储在 `longerThan3` 中
    println("numbers longer than 3 chars are $longerThan3")

将目标集合作为附加参数

例如用 filterTo() 代替 filter() 以及用 associateTo() 代替 associate()

val numbers = listOf("one", "two", "three", "four")
    val filterResults = mutableListOf<String>()  // 目标对象
    numbers.filterTo(filterResults) { it.length > 3 }
    numbers.filterIndexedTo(filterResults) { index, _ -> index == 0 }
    println(filterResults) // 包含两个操作的结果
// 将数字直接过滤到新的哈希集中,从而消除结果中的重复项
    val result = numbers.mapTo(HashSet()) { it.length }

写操作

写操作针对可变结合,包括添加、删除和更新元素,及排序等。写操作在集合写操作以及 List 写操作与 Map 写操作的相应部分中列出。
对于某些操作,有成对的函数可以执行相同的操作:一个函数就地应用该操作, 另一个函数将结果作为单独的集合返回。例如sort()sorted().

val numbers = mutableListOf("one", "two", "three", "four")
    val sortedNumbers = numbers.sorted() //生成了新的容器
    println(numbers == sortedNumbers)  // false
    numbers.sort() //还是原来的容器,只是状态变化了
    println(numbers == sortedNumbers)  // true

映射

映射 转换从另一个集合的元素上的函数结果创建一个集合。

val numbers = setOf(1, 2, 3)
    println(numbers.map { it * 3 })
    println(numbers.mapIndexed { idx, value -> value * idx })

合拢

合拢 转换是根据两个集合中具有相同位置的元素构建配对。

val colors = listOf("red", "brown", "grey")
    val animals = listOf("fox", "bear", "wolf")
    println(colors zip animals)
    val twoAnimals = listOf("fox", "bear")
    println(colors.zip(twoAnimals))

也可以使用带有两个参数的转换函数来调用 zip()

    val colors = listOf("red", "brown", "grey")
    val animals = listOf("fox", "bear", "wolf")
    println(colors.zip(animals) { color, animal -> "The ${animal.replaceFirstChar { it.uppercase() }} is $color"})

要分割键值对列表,请调用 unzip()

val numberPairs = listOf("one" to 1, "two" to 2, "three" to 3, "four" to 4)
    println(numberPairs.unzip())

关联

关联 转换允许从集合元素和与其关联的某些值构建 Map。

val numbers = listOf("one", "two", "three", "four")
    println(numbers.associateWith { it.length })

展平

如需操作嵌套的集合,那么可能会发现提供对嵌套集合元素进行打平访问的标准库函数很有用。

val numberSets = listOf(setOf(1, 2, 3), setOf(4, 5, 6), setOf(1, 2))
    println(numberSets.flatten())

另一个函数——flatMap(),flatMap() 表现为 map()(以集合作为映射结果)与 flatten() 的连续调用。

val containers = listOf(
        StringContainer(listOf("one", "two", "three")),
        StringContainer(listOf("four", "five", "six")),
        StringContainer(listOf("seven", "eight"))
    )
 //先取出`StringContainer`的values,然后再flatten操作
    println(containers.flatMap { it.values })

转字符串

以可读格式检索集合,使用joinToString()joinTo()
joinToString()根据提供的参数从集合生成String, joinTo()提供相同的操作,但是将结果给指定的 Appendable 对象。

val numbers = listOf("one", "two", "three", "four")
    println(numbers)
    println(numbers.joinToString())
    val listString = StringBuffer("The list of numbers: ")
//接收者作为参数传入
    numbers.joinTo(listString)
    println(listString)

指定joinToString参数,生成指定规则的String

   val numbers = listOf("one", "two", "three", "four")
    println(numbers.joinToString(separator = " | ", prefix = "start: ", postfix = ": end"))

大集合使用limit限制,超出的使用省略号替代truncated

val numbers = (1..100).toList()
//只生成前10个元素的字符串,超出部分用`<...>`代替
    println(numbers.joinToString(limit = 10, truncated = "<...>"))

定义元素形式本生使用transform函数

val numbers = listOf("one", "two", "three", "four")
    println(numbers.joinToString { "Element: ${it.uppercase()}"})

过滤

过滤分为一般filter过滤、划分、检验谓词

filter过滤

使用lambda形式的表达式filter,根据Boolean值结果返回true或者false进行过滤。

val numbers = listOf("one", "two", "three", "four")  
    val longerThan3 = numbers.filter { it.length > 3 }
    println(longerThan3)
	// filterIndexed(),带有元素索引和元素值
	val filteredIdx = numbers.filterIndexed { index, s -> (index != 0) && (s.length < 5)  }
	//否定条件来过滤, 那就是长度大于3的元素
    val filteredNot = numbers.filterNot { it.length <= 3 }

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

过滤指定类型使用filterIsInstance()
过滤不为空的filterNotNull()

val numbers = listOf(null, 1, "two", 3.0, "four")
//过滤出String类型的元素
numbers.filterIsInstance<String>().forEach {
          println(it.uppercase())
      }
//过滤掉空元素
numbers.filterNotNull().forEach {
      println(it.length)   // 对可空的 String 来说长度不可用
      }

划分

使用 partition(), 满足条件的放到一个List,不满足的放到另外个List,返回值是一个Pair类型的值。

val numbers = listOf("one", "two", "three", "four")
    val (match, rest) = numbers.partition { it.length > 3 }

检验谓词

  • 如果至少有一个元素匹配给定谓词,那么 any() 返回 true。
  • 如果没有元素与给定谓词匹配,那么 none() 返回 true。
  • 如果所有元素都匹配给定谓词,那么 all() 返回 true。 请注意,在一个空集合上使用任何有效的谓词去调用 all() 都会返回 true 。这种行为在逻辑上被称为 vacuous truth。
val numbers = listOf("one", "two", "three", "four")

    println(numbers.any { it.endsWith("e") }) //true
    println(numbers.none { it.endsWith("a") }) //true
    println(numbers.all { it.endsWith("e") })//false

    println(emptyList<Int>().all { it > 5 })   // vacuous truth

加减操作

集合定义了 plus (+) 和 minus (-) 操作符。第一个操作数为集合,第二个操作数为集合或者元素。

val numbers = listOf("one", "two", "three", "four")
val plusList = numbers + "five"
//如果第二次操作数是元素,那么移除第一次出现,如果是另一个集合那么移除所有出现
    val minusList = numbers - listOf("three", "four")

map的加减操作参考map章节,集合还定义了广义赋值操作符 plusAssign (+=)minusAssign (-=)

分组操作

使用函数 groupBy() 进行分组操作,使用一个 lambda 函数并返回一个 Map。

val numbers = listOf("one", "two", "three", "four", "five")
  println(numbers.groupBy { it.first().uppercase() })
    println(numbers.groupBy(keySelector = { it.first() }, valueTransform = { it.uppercase() }))

如果要对元素进行分组,然后一次将操作应用于所有分组,请使用 groupingBy() 函数。
Grouping 支持以下操作:

eachCount() 计算每个组中的元素。
fold()reduce() 对每个组分别执行 fold 与 reduce 操作,作为一个单独的集合并返回结果。
aggregate() 随后将给定操作应用于每个组中的所有元素并返回结果。 这是对 Grouping 执行任何操作的通用方法。当折叠或缩小不够时,可使用它来实现自定义操作。

val numbers = listOf("one", "two", "three", "four", "five", "six")
  println(numbers.groupingBy { it.first() }.eachCount())

获取部分集合

slice

slice() 返回具有给定索引的集合元素列表。

val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.slice(1..3))
    println(numbers.slice(0..4 step 2))
    println(numbers.slice(setOf(3, 5, 0)))

take 与 drop

从开头获取使用take()函数,从结尾获取使用 takeLast()函数。
要从头或从尾去除给定数量的元素,请调用 drop() dropLast() 函数。

val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.take(3))
    println(numbers.takeLast(3))
    println(numbers.drop(1))
    println(numbers.dropLast(5))

还有takeWhile() takeLastWhile()dropWhile()dropLastWhile()等函数

val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.takeWhile { !it.startsWith('f') })
    println(numbers.takeLastWhile { it != "three" })
    println(numbers.dropWhile { it.length == 3 })
    println(numbers.dropLastWhile { it.contains('i') })

chunked

要将集合分解为给定大小的“块”,请使用 chunked() 函数。

//每3个元素为一块
val numbers = (0..13).toList()
println(numbers.chunked(3))
println(numbers.chunked(3) { it.sum() })  // `it` 为原始集合的一个块

windowed

可以检索给定大小的集合元素中所有可能区间,函数称为 windowed()

val numbers = listOf("one", "two", "three", "four", "five")
    println(numbers.windowed(3))

执行结果:

[[one, two, three], [two, three, four], [three, four, five]]

windowed()提供可选参数

val numbers = (1..10).toList()
//step 定义两个相邻窗口的第一个元素之间的距离。
//partialWindows 包含从集合末尾的元素开始的较小的窗口。
    println(numbers.windowed(3, step = 2, partialWindows = true))
    println(numbers.windowed(3) { it.sum() })

执行结果:

[[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9], [9, 10]]
[6, 9, 12, 15, 18, 21, 24, 27]

要构建两个元素的窗口,有一个单独的函数——zipWithNext()

val numbers = listOf("one", "two", "three", "four", "five")
    println(numbers.zipWithNext())
    println(numbers.zipWithNext() { s1, s2 -> s1.length > s2.length})

执行结果:

[(one, two), (two, three), (three, four), (four, five)]
[false, false, true, false]

获取单个元素

list是有序的,可通过索引获取单个元素,set是无序的,但是一些子类实现是有序的。例如LinkedHashSet或者SortedSet
使用elementAt()获取指定位置元素
如果是List,则使用索引访问操作符 (get() 或 [])更为习惯。

检索第一个和最后一个元素分别使用first()last()函数。

为了避免获取元素出现异常,提供了elementAtOrNull()elementAtOrElse()等函数。

示例代码

val numbers = linkedSetOf("one", "two", "three", "four", "five")
    println(numbers.elementAt(3))

    val numbersSortedSet = sortedSetOf("one", "two", "three", "four")
    println(numbersSortedSet.elementAt(0))

val numbers = listOf("one", "two", "three", "four", "five")
    println(numbers.first())
    println(numbers.last())

	println(numbers.elementAtOrNull(5))
    println(numbers.elementAtOrElse(5) { index -> "The value for index $index is undefined"})

按条件获取

val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.first { it.length > 3 })
    println(numbers.last { it.startsWith("f") })
	//如果没有符合条件的,则返回null
	println(numbers.firstOrNull { it.length > 6 })

使用find()findLast()函数

val numbers = listOf(1, 2, 3, 4)
    println(numbers.find { it % 2 == 0 })
    println(numbers.findLast { it % 2 == 0 })

选择器检索

val list = listOf<Any>(0, "true", false)
    // 将每个元素转换为字符串,并返回具有所需长度的第一个元素,避免抛异常使用`firstNotNullOfOrNull()`
    val longEnough = list.firstNotNullOf { item -> item.toString().takeIf { it.length >= 4 } }
    println(longEnough)

随机取元素

使用random()函数,如果是空集合则使用randomOrNull(),避免抛出异常。

val numbers = listOf(1, 2, 3, 4)
    println(numbers.random())

检测元素存在与否

检查是否存在使用 contains()equals()containsAll()等函数
检查是否为null使用isEmpty() isNotEmpty() 等函数

val numbers = listOf("one", "two", "three", "four", "five", "six")
//检查是否存在
    println(numbers.contains("four"))
    println("zero" in numbers)
    println(numbers.containsAll(listOf("four", "two")))
	//判断是否为null
	println(numbers.isEmpty())
  println(numbers.isNotEmpty())

排序

自然排序:数值大小比较、字母顺序
自定义排序:需要实现Comparable接口的compareTo()方法

自然排序

val numbers = listOf("one", "two", "three", "four")

    println("Sorted ascending: ${numbers.sorted()}")
    println("Sorted descending: ${numbers.sortedDescending()}")

自定义排序

//定义`Comparator`排序
val lengthComparator = Comparator { str1: String, str2: String -> str1.length - str2.length }
    println(listOf("aaa", "bb", "c").sortedWith(lengthComparator))
//创建Comparator的简单方式`compareBy`
	println(listOf("aaa", "bb", "c").sortedWith(compareBy { it.length }))

	val numbers = listOf("one", "two", "three", "four")
    val sortedNumbers = numbers.sortedBy { it.length }
    println("Sorted by length ascending: $sortedNumbers")
	val sortedByLast = numbers.sortedByDescending { it.last() }
    println("Sorted by the last letter descending: $sortedByLast")

倒序

reversed() 返回带有元素副本的新集合。
asReversed()返回相同集合实例的一个反向视图,不会生成副本。
如果原始列表只读,那么使用asReversed()更轻量。

val numbers = listOf("one", "two", "three", "four")
    val reversedNumbers = numbers.asReversed()
    println(reversedNumbers)

	val mnumbers = mutableListOf("one", "two", "three", "four")
    val mreversedNumbers = mnumbers.asReversed()
    println(mreversedNumbers)
    mnumbers.add("five")
    println(mreversedNumbers)

随机顺序

shuffled() 函数返回一个包含了以随机顺序排序的集合元素的新的 List。

val numbers = listOf("one", "two", "three", "four")
//也可以传入Random对象
    println(numbers.shuffled())

聚合操作

通用操作

常用的聚合操作函数如下:

  • minOrNull()maxOrNull() 分别返回最小和最大的元素。 空集合返回空。
  • average() 返回数字集合中元素的平均值。
  • sum() 返回数字集合中元素的总和。
  • count() 返回集合中元素的数量。
    示例代码:
val numbers = listOf(6, 42, 10, 4)

    println("Count: ${numbers.count()}")
    println("Max: ${numbers.maxOrNull()}")
    println("Min: ${numbers.minOrNull()}")
    println("Average: ${numbers.average()}")
    println("Sum: ${numbers.sum()}")

还有其他一些函数:
maxByOrNull()minByOrNull()
maxWithOrNull() minWithOrNull()
maxOfOrNull() and minOfOrNull()
maxOfWithOrNull() and minOfWithOrNull()
示例代码:

val numbers = listOf(5, 42, 10, 4)
    val min3Remainder = numbers.minByOrNull { it % 3 }
    println(min3Remainder)

    val strings = listOf("one", "two", "three", "four")
    val longestString = strings.maxWithOrNull(compareBy { it.length })
    println(longestString)

	println(numbers.sumOf { it * 2 })
    println(numbers.sumOf { it.toDouble() / 2 })

fold 与 reduce

函数 reduce()fold(),它们依次将所提供的操作应用于集合元素并返回累积的结果。 操作有两个参数:先前的累积值和集合元素。
区别在于:fold() 接受一个初始值并将其用作第一步的累积值,而 reduce() 的第一步则将第一个和第二个元素作为第一步的操作参数。
示例代码:

val numbers = listOf(5, 2, 10, 4)

    val simpleSum = numbers.reduce { sum, element -> sum + element }
    println(simpleSum) //21
	//第一个元素未加倍
	val sumDoubled = numbers.reduce { sum, element -> sum + element * 2 }
	println(sumDoubled) //37
	//第一个元素加倍,跟上面计算不同
    val sumDoubled1 = numbers.fold(0) { sum, element -> sum + element * 2 }
    println(sumDoubled1) //42

反向操作使用函数 reduceRight()foldRight() ,从最后一个元素开始,然后再继续到前一个元素。
操作参数会更改其顺序:第一个参数变为元素,然后第二个参数变为累积值。

 val numbers = listOf(5, 2, 10, 4)
    val sumDoubledRight = numbers.foldRight(0) { element, sum -> sum + element * 2 }
    println(sumDoubledRight)

带上元素索引使用 reduceIndexed()foldIndexed(),同理有反向函数——reduceRightIndexed()foldRightIndexed()
还有一些对null安全的处理函数
reduceOrNull()
reduceRightOrNull()
reduceIndexedOrNull()
reduceRightIndexedOrNull()
如需保存中间累加值的使用 runningFold() (或者相同方法 scan()) 与 runningReduce().
示例代码:

val numbers = listOf(0, 1, 2, 3, 4, 5)
    val runningReduceSum = numbers.runningReduce { sum, item -> sum + item }
    val runningFoldSum = numbers.runningFold(10) { sum, item -> sum + item }
//sampleEnd
    val transform = { index: Int, element: Int -> "N = ${index + 1}: $element" }
    println(runningReduceSum.mapIndexed(transform).joinToString("\n", "Sum of first N elements with runningReduce:\n"))
    println(runningFoldSum.mapIndexed(transform).joinToString("\n", "Sum of first N elements with runningFold:\n"))

执行结果:

Sum of first N elements with runningFold:
N = 1: 10
N = 2: 10
N = 3: 11
N = 4: 13
N = 5: 16
N = 6: 20
N = 7: 25

写操作

支持MutableCollection类型的数据结构,如List、Set。

还可以使用 plus 运算符 - plusAssign (+=) 添加元素。

添加元素

使用add()addAll()函数

val numbers = mutableListOf(1, 2, 3, 4)
    numbers.add(5)
	numbers.addAll(arrayOf(7, 8))
    println(numbers)
	//指定位置插入
    numbers.addAll(2, setOf(3, 4))
    println(numbers)

使用plus运算符

val numbers = mutableListOf("one", "two")
    numbers += "three"
    println(numbers)
    numbers += listOf("four", "five")
    println(numbers)

删除操作

使用remove()clear()retainAll()removeAll()等函数。
retainAll():与 removeAll() 相反:它移除除参数集合中的元素之外的所有元素, 可以添加过滤条件。
示例代码:

val numbers = mutableListOf(1, 2, 3, 4, 3)
    numbers.remove(3)                    // 删除了第一个 `3`
    println(numbers)
    numbers.remove(5)                    // 什么都没删除
    println(numbers)
	numbers.retainAll { it >= 3 }
    println(numbers)
    numbers.clear()
    println(numbers)

    val numbersSet = mutableSetOf("one", "two", "three", "four")
    numbersSet.removeAll(setOf("one", "two"))
    println(numbersSet)

使用 minusAssign (-=) ——原地修改版的 minus 操作符

 val numbers = mutableListOf("one", "two", "three", "three", "four")
    numbers -= "three"
    println(numbers)
    numbers -= listOf("four", "five")
    //numbers -= listOf("four")    // 与上述相同
    println(numbers)

更新操作

List及Map分别提供,Set更新无意义

List专有操作

List操作包括按索引取元素、取列表的一部分、查找元素位置(线性查找、有序列表二分查找、Comparator 二分搜索、比较函数二分搜索) 、写操作(添加、更新、删除、排序)

按索引取元素

elementAt() 集合方法根据索引获取元素
first() 获取第一个元素
last()获取最后一个元素
get()或者[index] List方法
List 长度小于指定的索引,则抛出异常。 另外,还有两个函数能避免此类异常:
getOrElse() 提供用于计算默认值的函数,如果集合中不存在索引,则返回默认值。
getOrNull() 返回 null 作为默认值
示例代码

val numbers = listOf(1, 2, 3, 4)
    println(numbers.get(0))
    println(numbers[0])
    //numbers.get(5)                         // exception!
    println(numbers.getOrNull(5))             // null
    println(numbers.getOrElse(5, {it}))        // 5

取列表一部分

集合的取列表部分的操作仍然适用,List还提供了subList方法。该方法是引用操作,并不是副本操作。原始列表或者子列表变更都会引起另一个的变更。

val numbers = (0..13).toList()
    println(numbers.subList(3, 6))

查找之线性查找

使用 indexOf()lastIndexOf() 函数找到元素的位置
调用成功则返回位置索引,不成功返回-1

还有如下方法:
indexOfFirst() 返回与谓词匹配的第一个元素的索引,如果没有此类元素,则返回 -1。
indexOfLast() 返回与谓词匹配的最后一个元素的索引,如果没有此类元素,则返回 -1。
示例代码:

val numbers = mutableListOf(1, 2, 3, 4)
    println(numbers.indexOfFirst { it > 2})
    println(numbers.indexOfLast { it % 2 == 1})

查找之二分查找

二分查找需要列表有序,效率较高
调用函数 binarySearch(),成功返回索引,失败返回-insertionPoint - 1,其中 insertionPoint 为应插入此元素的索引
示例代码:

val numbers = mutableListOf("one", "two", "three", "four")
    numbers.sort()
    println(numbers)
    println(numbers.binarySearch("two"))  // 3
    println(numbers.binarySearch("z")) // -5
    println(numbers.binarySearch("two", 0, 2))  // -3

执行结果:

[four, one, three, two]
3
-5
-3

查找之Comparator二分搜索

如果列表元素不是 Comparable,则应提供一个用于二分搜索的 Comparator。 该列表必须根据此 Comparator 以升序排序。
示例代码:

data class Product(val name: String, val price: Double)

fun main() {
//sampleStart
    val productList = listOf(
        Product("WebStorm", 49.0),
        Product("AppCode", 99.0),
        Product("DotTrace", 129.0),
        Product("ReSharper", 149.0))

    println(productList.binarySearch(Product("AppCode", 99.0), compareBy<Product> { it.price }.thenBy { it.name }))
//sampleEnd
}

按照价格升序排列,然后使用二分法搜索。

按照字母排序,不区分大小写

val colors = listOf("Blue", "green", "ORANGE", "Red", "yellow")
    println(colors.binarySearch("RED", String.CASE_INSENSITIVE_ORDER)) // 3

查找之比较函数二分搜索

比较函数将元素映射到 Int 值,并搜索函数返回 0 的元素。 该列表必须根据提供的函数以升序排序;换句话说, 比较的返回值必须从一个列表元素增长到下一个列表元素。

import kotlin.math.sign
//sampleStart
data class Product(val name: String, val price: Double)

fun priceComparison(product: Product, price: Double) = sign(product.price - price).toInt()

fun main() {
    val productList = listOf(
        Product("WebStorm", 49.0),
        Product("AppCode", 99.0),
        Product("DotTrace", 129.0),
        Product("ReSharper", 149.0))

    println(productList.binarySearch { priceComparison(it, 99.0) })
}
//sampleEnd

写操作之添加

除了集合写操作中描述的集合修改操作之外, 可变列表还支持特定的写操作。
使用 add()addAll() 并提供元素插入的位置作为附加参数。 位置之后的所有元素都将向右移动

val numbers = mutableListOf("one", "five", "six")
    numbers.add(1, "two")
    numbers.addAll(2, listOf("three", "four"))
    println(numbers)

写操作之更新

set() 及其操作符形式 []set() 不会更改其他元素的索引。
示例代码:

val numbers = mutableListOf("one", "five", "three")
    numbers[1] =  "two"
    println(numbers)

fill() 简单地将所有集合元素的值替换为指定值

val numbers = mutableListOf(1, 2, 3, 4)
//所有元素都替换成了3
    numbers.fill(3)

写操作之删除

使用 removeAt() 函数,删除元素之后的所有元素索引都减1

val numbers = mutableListOf(1, 2, 3, 4, 3)
    numbers.removeAt(1)

写操作之排序

集合排序方法与列表排序方法稍有差异
sort* 在所有排序函数的名称中代替 sorted*sort()sortDescending()sortBy() 等等。
shuffle() 代替 shuffled()。
reverse() 代替 reversed()。
asReversed() 在可变列表上调用会返回另一个可变列表,该列表是原始列表的反向视图。
示例代码

val numbers = mutableListOf("one", "two", "three", "four")

    numbers.sort()
    println("Sort into ascending: $numbers")
    numbers.sortDescending()
    println("Sort into descending: $numbers")

    numbers.sortBy { it.length }
    println("Sort into ascending by length: $numbers")
    numbers.sortByDescending { it.last() }
    println("Sort into descending by the last letter: $numbers")

    numbers.sortWith(compareBy<String> { it.length }.thenBy { it })
    println("Sort by Comparator: $numbers")

    numbers.shuffle()
    println("Shuffle: $numbers")

    numbers.reverse()
    println("Reverse: $numbers")

Set专有操作

常用操作:找出集合间的交集、并集或差集。
并集: union()或者a union b
交集:intersect()或者a intersect b
差集: subtract() 或者a subtract b
示例:

val numbers = setOf("one", "two", "three")

    println(numbers union setOf("four", "five"))
    println(setOf("four", "five") union numbers)

    println(numbers intersect setOf("two", "one"))
    println(numbers subtract setOf("three", "four"))
    println(numbers subtract setOf("four", "three")) // 相同的输出

上述操作同样适用于List

val list1 = listOf(1, 1, 2 ,3, 5, 8, -1)
    val list2 = listOf(1, 1, 2, 2 ,3, 5)
    println(list1 intersect list2) // result on two lists is a Set
    println(list1 union list2)

Map专有操作

Map操作分为读操作和写操作,读操作包括获取键与值、过滤、加减操作符。写操作包括添加更新条目、删除条目

Map读操作

取键和值

根据键获取值:get()函数或者[key]
根据值获取键: getValue()
getOrElse() 对于不存在的键,其值由给定的 lambda 表达式返回
getOrDefault() 如果找不到键,则返回指定的默认值.

val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
    println(numbersMap.get("one"))
    println(numbersMap["one"])
    println(numbersMap.getOrDefault("four", 10))
    println(numbersMap["five"])               // null
    //numbersMap.getValue("six")      // exception!
//检索所有的键和值
 	println(numbersMap.keys)
    println(numbersMap.values)

过滤

使用filter函数
按照键过滤使用filterKeys()
按照值过滤使用filterValues()

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
    val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10}
//分别根据键和值过滤
	val filteredKeysMap = numbersMap.filterKeys { it.endsWith("1") }
    val filteredValuesMap = numbersMap.filterValues { it < 10 }
    println(filteredKeysMap)
    println(filteredValuesMap)

加减操作符

使用plus(+)与 minus (-)

val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
    println(numbersMap + Pair("four", 4))
    println(numbersMap + Pair("one", 10))
    println(numbersMap + mapOf("five" to 5, "one" to 11))

	println(numbersMap - "one")
    println(numbersMap - listOf("two", "four"))

Map写操作

写操作针对Mutable类型的Map,遵循下列原则:

  • 值可以更新。 反过来,键也永远不会改变:添加条目后,键是不变的。
  • 每个键都有一个与之关联的值。也可以添加和删除整个条目。

添加与更新条目

添加单个条目使用put(), 添加多个使用putAll()

在 Map 类中,新元素的位置由其键顺序定义

如果给定键已存在于 Map 中,则 put() 与 putAll() 都将覆盖值。 因此,可以使用它们来更新 Map 条目的值。

val numbersMap = mutableMapOf("one" to 1, "two" to 2)
    numbersMap.put("three", 3)
	
	//(1) put的key'相同则覆盖对应的值
	val previousValue = numbersMap.put("one", 11)
	
//(2) 参数可以是 Map 或一组 Pair : Iterable 、 Sequence 或 Array
    numbersMap.putAll(setOf("four" to 4, "five" to 5))
	
	//(3) 使用快捷操作符`+=`、`[]`
	//plusAssign (+=) 操作符。
   //[] 操作符为 set() 的别名
	numbersMap["three"] = 3     // 调用 numbersMap.put("three", 3)
    numbersMap += mapOf("four" to 4, "five" to 5)
    println(numbersMap)

删除条目

使用remove()函数,可以传递键或整个键值对,传入键值对时候需要键和值都匹配才能删除。

val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3)
    numbersMap.remove("one")
    println(numbersMap)
    numbersMap.remove("three", 4)            //不会删除任何条目
    println(numbersMap)
//使用`.keys` 或 `.values` 中调用 remove() 并提供键或值来删除条目,使用`.values`时仅删除第一个匹配的条目
   numbersMap.keys.remove("one")
    println(numbersMap)
    numbersMap.values.remove(3)
    println(numbersMap)
//`minusAssign (-=)` 操作符也可用于可变 Map
    numbersMap -= "two"
    println(numbersMap)
    numbersMap -= "five"             //不会删除任何条目
    println(numbersMap)

官方文档之集合

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-09-30 01:04:20  更:2022-09-30 01:04:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 21:51:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码