Kotlin学习笔记18——list,map,set相关操作

前言

上一篇我们学习了Kotlin中集合公共操作,今天继续来学习Kotlin中的集合。集合的内容包含的比较多,分为三篇来学习,今天是第三篇我们学习list,map,set相关特定API操作,算是对上篇公共操作的一个补充。

List

List 是 Kotlin 标准库中最受欢迎的集合类型。对列表元素的索引访问为 List 提供了一组强大的操作。

按索引取元素

List 支持按索引取元素的所有常用操作: elementAt() 、 first() 、 last() 与取单个元素中列出的其他操作。 List 的特点是能通过索引访问特定元素,因此读取元素的最简单方法是按索引检索它。 这是通过 get() 函数或简写语法 [index] 来传递索引参数完成的。

如果 List 长度小于指定的索引,则抛出异常。 另外,还有两个函数能避免此类异常:

  • getOrElse() :提供用于计算默认值的函数,如果集合中不存在索引,则返回默认值。
  • getOrNull():返回 null 作为默认值。
val numbers = listOf(1, 2, 3, 4)
println(numbers.get(0))//结果:1
println(numbers[0])//结果:1
//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。

val numbers = listOf(1, 2, 3, 4, 2, 5)
println(numbers.indexOf(2))
println(numbers.lastIndexOf(2))

还有一对函数接受谓词并搜索与之匹配的元素:

  • indexOfFirst(): 返回与谓词匹配的第一个元素的索引,如果没有此类元素,则返回 -1。
  • indexOfLast(): 返回与谓词匹配的最后一个元素的索引,如果没有此类元素,则返回 -1。

注意这里的谓词匹配就是后面接lambda表达式里面条件筛选,如下:

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

Comparator 二分搜索

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

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 }))

这是一个不可排序的 Product 实例列表,以及一个定义排序的 Comparator:如果 p1 的价格小于 p2 的价格,则产品 p1 在产品 p2 之前。 因此,按照此顺序对列表进行升序排序后,使用 binarySearch() 查找指定的 Product的索引。

当列表使用与自然排序不同的顺序时(例如,对 String 元素不区分大小写的顺序),自定义 Comparator 也很方便。

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

比较函数二分搜索

使用 比较 函数的二分搜索无需提供明确的搜索值即可查找元素。 取而代之的是,它使用一个比较函数将元素映射到 Int 值,并搜索函数返回 0 的元素。 该列表必须根据提供的函数以升序排序;换句话说,比较的返回值必须从一个列表元素增长到下一个列表元素。

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) })
}

Comparator 与比较函数二分搜索都可以针对列表区间执行。

List 写操作

添加

要将元素添加到列表中的特定位置,请使用 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)
numbers.fill(3)
println(numbers)//结果:[3, 3, 3, 3]

删除

要从列表中删除指定位置的元素,请使用 removeAt() 函数,并将位置作为参数。 在元素被删除之后出现的所有元素索引将减 1。

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

Map

在 map 中,键和值的类型都是用户定义的。 对基于键的访问启用了各种特定于 map 的处理函数,从键获取值到对键和值进行单独过滤。

取键与值

要从 Map 中检索值,必须提供其键作为 get() 函数的参数。 还支持简写 [key] 语法。 如果找不到给定的键,则返回 null 。 还有一个函数 getValue() ,它的行为略有不同:如果在 Map 中找不到键,则抛出异常。 此外,还有两个选项可以解决键缺失的问题:

  • getOrElse() :与 list 的工作方式相同:对于不存在的键,其值由给定的 lambda 表达式返回。
  • getOrDefault() :如果找不到键,则返回指定的默认值。
val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap.get("one"))//结果:1
println(numbersMap["one"])//结果:1
println(numbersMap.getOrDefault("four", 10))//结果:10
println(numbersMap["five"])//结果:null      

要对 map 的所有键或所有值执行操作,可以从属性 keys 和 values 中相应地检索它们。 keys 是 Map 中所有键的集合, values 是 Map 中所有值的集合。

val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap.keys)
println(numbersMap.values)

过滤

可以使用 filter() 函数来过滤 map 或其他集合。 对 map 使用 filter() 函数时, Pair 将作为参数的谓词传递给它。 它将使用谓词同时过滤其中的键和值。

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

还有两种用于过滤 map 的特定函数:按键或按值。 这两种方式,都有对应的函数: filterKeys() 和 filterValues() 。 两者都将返回一个新 Map ,其中包含与给定谓词相匹配的条目。 filterKeys() 的谓词仅检查元素键, filterValues() 的谓词仅检查值。

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
val filteredKeysMap = numbersMap.filterKeys {
    
     it.endsWith("1") }
val filteredValuesMap = numbersMap.filterValues {
    
     it < 10 }

println(filteredKeysMap)//结果:{key1=1, key11=11}
println(filteredValuesMap)//结果:{key1=1, key2=2, key3=3}

plus 与 minus 操作

由于需要访问元素的键,plus(+)与 minus(-)运算符对 map 的作用与其他集合不同。 plus 返回包含两个操作数元素的 Map :左侧的 Map 与右侧的 Pair 或另一个 Map 。 当右侧操作数中有左侧 Map 中已存在的键时,该条目将使用右侧的值。

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))

minus 将根据左侧 Map 条目创建一个新 Map ,右侧操作数带有键的条目将被剔除。 因此,右侧操作数可以是单个键或键的集合: list 、 set 等。

val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap - "one")
println(numbersMap - listOf("two", "four"))

Map 写操作

Mutable Map (可变 Map )提供特定的 Map 写操作。 这些操作使你可以使用键来访问或更改 Map 值。Map 写操作的一些规则:

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

添加与更新条目

要将新的键值对添加到可变 Map ,请使用 put() 。 将新条目放入 LinkedHashMap (Map的默认实现)后,会添加该条目,以便在 Map 迭代时排在最后。 在 Map 类中,新元素的位置由其键顺序定义。

val numbersMap = mutableMapOf("one" to 1, "two" to 2)
numbersMap.put("three", 3)
println(numbersMap)//结果:{one=1, two=2, three=3}

要一次添加多个条目,请使用 putAll() 。它的参数可以是 Map 或一组 Pair : Iterable 、 Sequence 或 Array 。

val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3)
numbersMap.putAll(setOf("four" to 4, "five" to 5))
println(numbersMap)//结果:{one=1, two=2, three=3, four=4, five=5}

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

val numbersMap = mutableMapOf("one" to 1, "two" to 2)
val previousValue = numbersMap.put("one", 11)
//结果:value associated with 'one', before: 1, after: 11
println("value associated with 'one', before: $previousValue, after: ${numbersMap["one"]}")
println(numbersMap)//结果:{one=11, two=2}

还可以使用快速操作符将新条目添加到 Map 。 有两种方式:

  • lusAssign (+=) 操作符。
  • [] 操作符为 put() 的别名。
val numbersMap = mutableMapOf("one" to 1, "two" to 2)
numbersMap["three"] = 3     // 调用 numbersMap.put("three", 3)
numbersMap += mapOf("four" to 4, "five" to 5)
println(numbersMap)

删除条目

要从可变 Map 中删除条目,请使用 remove() 函数。 调用 remove() 时,可以传递键或整个键值对。 如果同时指定键和值,则仅当键值都匹配时,才会删除此的元素。

val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3)
numbersMap.remove("one")
println(numbersMap)//结果:{two=2, three=3}
numbersMap.remove("three", 4)            //不会删除任何条目
println(numbersMap)//结果:{two=2, three=3}

还可以通过键或值从可变 Map 中删除条目。 在 Map 的 .keys 或 .values 中调用 remove() 并提供键或值来删除条目。 在 .values 中调用时, remove() 仅删除给定值匹配到的的第一个条目。

val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3, "threeAgain" to 3)
numbersMap.keys.remove("one")
println(numbersMap)//结果:{two=2, three=3, threeAgain=3}
numbersMap.values.remove(3)
println(numbersMap)//结果:{two=2, threeAgain=3}

minusAssign (-=) 操作符也可用于可变 Map 。

val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3)
numbersMap -= "two"
println(numbersMap)
numbersMap -= "five"             //不会删除任何条目
println(numbersMap)

Set

Kotlin 集合包中包含 set 常用操作的扩展函数:查找交集、并集或差集。

要将两个集合合并为一个(并集),可使用 union() 函数。也能以中缀形式使用 a union b。 注意,对于有序集合,操作数的顺序很重要:在结果集合中,左侧操作数在前。

要查找两个集合中都存在的元素(交集),请使用 intersect() 。 要查找另一个集合中不存在的集合元素(差集),请使用 subtract() 。 这两个函数也能以中缀形式调用,例如, a intersect 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")) // 相同的输出

结果:

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

尾巴

今天的学习笔记就先到这里了,集合到这里基本学习的差不多了。
老规矩,喜欢我的文章,欢迎素质三连:点赞,评论,关注,谢谢大家!

猜你喜欢

转载自blog.csdn.net/abs625/article/details/107084403
今日推荐