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

    技术2022-07-15  37

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

    前言List按索引取元素取列表的一部分查找元素位置线性查找在有序列表中二分查找Comparator 二分搜索比较函数二分搜索 List 写操作添加更新删除 Map取键与值过滤plus 与 minus 操作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]

    尾巴

    今天的学习笔记就先到这里了,集合到这里基本学习的差不多了。下一篇我们将学习内置函数之 let 、also、apply、run、with 老规矩,喜欢我的文章,欢迎素质三连:点赞,评论,关注,谢谢大家!

    Processed: 0.015, SQL: 9