Kotlin集合使用

1、集合类型

Kotlin 标准库提供了基本集合类型的实现: set、list 以及 map。 一对接口代表每种集合类型:

1、一个 只读 接口,提供访问集合元素的操作。
2、一个 可变 接口,通过写操作扩展相应的只读接口:添加、删除和更新其元素。

请注意,更改可变集合不需要它是以 var 定义的变量:写操作修改同一个可变集合对象,因此引用不会改变。 但是,如果尝试对 val 集合重新赋值,你将收到编译错误。

val numbers = mutableListOf("one", "two", "three", "four")
numbers.add("five")   // 这是可以的
//numbers = mutableListOf("six", "seven")      // 编译错误

2、List

List 以指定的顺序存储元素,并提供使用索引访问元素的方法。索引从 0 开始 – 第一个元素的索引 – 直到 最后一个元素的索引(list.size - 1)

val numbers = listOf("one", "two", "three", "four")
println("Number of elements: ${numbers.size}")
println("Third element: ${numbers.get(2)}")
println("Fourth element: ${numbers[3]}")
println("Index of element \"two\" ${numbers.indexOf("two")}")

MutableList 是可以进行写操作的 List,例如用于在特定位置添加或删除元素。

val numbers = mutableListOf(1, 2, 3, 4)
numbers.add(5)
numbers.removeAt(1)
numbers[0] = 0
numbers.shuffle()
println(numbers)

3、Map

Map 不是 Collection 接口的继承者;但是它也是 Kotlin 的一种集合类型。 Map 存储 键-值 对(或 条目);键是唯一的,但是不同的键可以与相同的值配对。Map 接口提供特定的函数进行通过键访问值、搜索键和值等操作。

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)
println("All keys: ${numbersMap.keys}")
println("All values: ${numbersMap.values}")
if ("key2" in numbersMap) println("Value by key \"key2\": ${numbersMap["key2"]}")    
if (1 in numbersMap.values) println("The value 1 is in the map")
if (numbersMap.containsValue(1)) println("The value 1 is in the map") // 同上

MutableMap 是一个具有写操作的 Map 接口,可以使用该接口添加一个新的键值对或更新给定键的值。

val numbersMap = mutableMapOf("one" to 1, "two" to 2)
numbersMap.put("three", 3)
numbersMap["one"] = 11
println(numbersMap)

4、集合的类型

创建集合的最常用方法是使用标准库函数
listOf()
setOf()
mutableListOf()
mutableSetOf()

Map 也有这样的函数
mapOf()
mutableMapOf()

5、空集合

还有用于创建没有任何元素的集合的函数:emptyList()emptySet()emptyMap()。 创建空集合时,应指定集合将包含的元素类型。

val empty = emptyList()

6、具体类型构造函数

要创建具体类型的集合,例如 ArrayList 或 LinkedList,可以使用这些类型的构造函数。 类似的构造函数对于 Set 与 Map 的各实现中均有提供。

val linkedList = LinkedList(listOf("one", "two", "three"))
val presizedSet = HashSet(32)

7、复制

要创建与现有集合具有相同元素的集合,可以使用复制操作。标准库中的集合复制操作创建了具有相同元素引用的 复制集合。 因此,对集合元素所做的更改会反映在其所有副本中。

在特定时刻通过集合复制函数,例如toList()toMutableList()toSet() 等等。创建了集合的快照。 结果是创建了一个具有相同元素的新集合 如果在源集合中添加或删除元素,则不会影响副本。副本也可以独立于源集合进行更改。

//原数组
val sourceList = mutableListOf(1, 2, 3)
//复制成可变数组
val copyList = sourceList.toMutableList()
//复制成只读数组
val readOnlyCopyList = sourceList.toList()
sourceList.add(4)
println("Copy size: ${copyList.size}")   

//readOnlyCopyList.add(4)             // 编译异常
println("Read-only copy size: ${readOnlyCopyList.size}")

这些函数还可用于将集合转换为其他类型,例如根据 List 构建 Set,反之亦然。

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

8、迭代器

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

遍历 Iterable 集合的另一种方法是众所周知的 for 循环。在集合中使用 for 循环时,将隐式获取迭代器。因此,以下代码与上面的示例等效:

//迭代器 2
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)
}

9、可变迭代器

为了迭代可变集合,于是有了 MutableIterator 来扩展 Iterator 使其具有元素删除函数 remove() 。因此,可以在迭代时从集合中删除元素。

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

mutableIterator.next()
mutableIterator.remove()    
println("After removal: $numbers")

10、区间与数列

Kotlin 可通过调用 kotlin.ranges 包中的 rangeTo() 函数及其操作符形式的 .. 轻松地创建两个值的区间。 通常,rangeTo() 会辅以 in!in 函数。

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

整数类型区间(IntRangeLongRangeCharRange)还有一个拓展特性:可以对其进行迭代。 这些区间也是相应整数类型的等差数列。 这种区间通常用于 for 循环中的迭代。

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)
for (i in 8 downTo 1 step 2) print(i)

要迭代不包含其结束元素的数字区间,请使用 until 函数:

for (i in 1 until 10) {       // i in [1, 10), 10被排除
    print(i)
}

11、 映射

映射 转换从另一个集合的元素上的函数结果创建一个集合。 基本的映射函数是 map()。 它将给定的 lambda 函数应用于每个后续元素,并返回 lambda 结果列表。 结果的顺序与元素的原始顺序相同。 如需应用还要用到元素索引作为参数的转换,请使用 mapIndexed()

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

如果转换在某些元素上产生 null 值,则可以通过调用 mapNotNull() 函数取代 map()mapIndexedNotNull() 取代 mapIndexed() 来从结果集中过滤掉 null 值。

val numbers = setOf(1, 2, 3)
println(numbers.mapNotNull { if ( it == 2) null else it * 3 })
println(numbers.mapIndexedNotNull { idx, value -> if (idx == 0) null else value * idx })

12、字符串表示

如果需要以可读格式检索集合内容,请使用将集合转换为字符串的函数:joinToString()joinTo()

joinToString() 根据提供的参数从集合元素构建单个 StringjoinTo() 执行相同的操作,但将结果附加到给定的 Appendable 对象。

当使用默认参数调用时,函数返回的结果类似于在集合上调用 toString():各元素的字符串表示形式以空格分隔而成的 String

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

println(numbers)         
println(numbers.joinToString())

val listString = StringBuffer("The list of numbers: ")
numbers.joinTo(listString)
println(listString)

13、过滤

基本的过滤函数是 filter()。当使用一个谓词来调用时,filter() 返回与其匹配的集合元素。对于 ListSet,过滤结果都是一个 List,对 Map 来说结果还是一个 Map

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

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)

filter() 中的谓词只能检查元素的值。如果想在过滤中使用元素在集合中的位置,应该使用 filterIndexed()。它接受一个带有两个参数的谓词:元素的索引和元素的值。

如果想使用否定条件来过滤集合,请使用 filterNot()。它返回一个让谓词产生 false 的元素列表。

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

val filteredIdx = numbers.filterIndexed { index, s -> (index != 0) && (s.length < 5)  }
val filteredNot = numbers.filterNot { it.length <= 3 }

println(filteredIdx)
println(filteredNot)

14、plus 与 minus 操作符

在 Kotlin 中,为集合定义了 plus (+) 和 minus (-) 操作符。 它们把一个集合作为第一个操作数;第二个操作数可以是一个元素或者是另一个集合。 返回值是一个新的只读集合:

  • plus 的结果包含原始集合 第二个操作数中的元素。
  • minus 的结果包含原始集合中的元素,但第二个操作数中的元素 除外。 如果第二个操作数是一个元素,那么 minus 移除其在原始集合中的 第一次 出现;如果是一个集合,那么移除其元素在原始集合中的 所有 出现。
val numbers = listOf("one", "two", "three", "four")

val plusList = numbers + "five"
val minusList = numbers - listOf("three", "four")
println(plusList)
println(minusList)

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

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

17、取单个元素-按位置取

为了检索特定位置的元素,有一个函数 elementAt()。 用一个整数作为参数来调用它,你会得到给定位置的集合元素。 第一个元素的位置是 0,最后一个元素的位置是 (size - 1)

elementAt() 对于不提供索引访问或非静态已知提供索引访问的集合很有用。 在使用 List 的情况下,使用索引访问操作符 (get()[])更为习惯

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

val numbersSortedSet = sortedSetOf("one", "two", "three", "four")
println(numbersSortedSet.elementAt(0)) // 元素以升序存储
//还有一些有用的别名来检索集合的第一个和最后一个元素:first() 和 last()
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.first())    
println(numbers.last())  

为了避免在检索位置不存在的元素时出现异常,请使用 elementAt() 的安全变体:

  • 当指定位置超出集合范围时,elementAtOrNull() 返回 null。
  • elementAtOrElse() 还接受一个 lambda 表达式,该表达式能将一个 Int 参数映射为一个集合元素类型的实例。 当使用一个越界位置来调用时,elementAtOrElse() 返回对给定值调用该 lambda 表达式的结果。
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.elementAtOrNull(5))
println(numbers.elementAtOrElse(5) { index -> "The value for index $index is undefined"})

18、取单个元素-按条件取

函数 first()last() 还可以让你在集合中搜索与给定谓词匹配的元素。 当你使用测试集合元素的谓词调用 first() 时,你会得到对其调用谓词产生 true 的第一个元素。 反过来,带有一个谓词的 last() 返回与其匹配的最后一个元素。

val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.first { it.length > 3 })
println(numbers.last { it.startsWith("f") })

如果没有元素与谓词匹配,两个函数都会抛异常。 为了避免它们,请改用 firstOrNull()lastOrNull():如果找不到匹配的元素,它们将返回 null

val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.firstOrNull { it.length > 6 })

19、随机取元素

如果需要检索集合的一个随机元素,那么请调用 random() 函数。 你可以不带参数或者使用一个 Random 对象作为随机源来调用它。

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

20、检测存在与否

如需检查集合中某个元素的存在,可以使用 contains() 函数。 如果存在一个集合元素等于(equals())函数参数,那么它返回 true。 你可以使用 in 关键字以操作符的形式调用 contains()

如需一次检查多个实例的存在,可以使用这些实例的集合作为参数调用 containsAll()

val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.contains("four"))
println("zero" in numbers)

println(numbers.containsAll(listOf("four", "two")))
println(numbers.containsAll(listOf("one", "zero")))

此外,你可以通过调用 isEmpty()isNotEmpty() 来检查集合中是否包含任何元素。

val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.isEmpty())
println(numbers.isNotEmpty())

val empty = emptyList()
println(empty.isEmpty())
println(empty.isNotEmpty())

21、 自然顺序

基本的函数 sorted()sortedDescending() 返回集合的元素,这些元素按照其自然顺序升序和降序排序。 这些函数适用于 Comparable 元素的集合。

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

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

22、 自定义顺序

为了按照自定义顺序排序或者对不可比较对象排序,可以使用函数 sortedBy()sortedByDescending()。 它们接受一个将集合元素映射为 Comparable 值的选择器函数,并以该值的自然顺序对集合排序。

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

23、倒序

你可以使用 reversed() 函数以相反的顺序检索集合。

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

reversed() 返回带有元素副本的新集合。 因此,如果你之后改变了原始集合,这并不会影响先前获得的 reversed() 的结果。

另一个反向函数——asReversed()——返回相同集合实例的一个反向视图,因此,如果原始列表不会发生变化,那么它会比 reversed() 更轻量,更合适。

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

24、 随机顺序

最后,shuffled() 函数返回一个包含了以随机顺序排序的集合元素的新的 List。 你可以不带参数或者使用 Random 对象来调用它。

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

25、集合聚合操作

Kotlin 集合包含用于常用的 聚合操作 (基于集合内容返回单个值的操作)的函数 。 其中大多数是众所周知的,并且其工作方式与在其他语言中相同。

  • min()max() 分别返回最小和最大的元素;
  • average() 返回数字集合中元素的平均值;
  • sum() 返回数字集合中元素的总和;
  • count() 返回集合中元素的数量;
val numbers = listOf(6, 42, 10, 4)
println("Count: ${numbers.count()}")
println("Max: ${numbers.max()}")
println("Min: ${numbers.min()}")
println("Average: ${numbers.average()}")
println("Sum: ${numbers.sum()}")

26、集合写操作

可变集合支持更改集合内容的操作,例如添加或删除元素。 在此页面上,我们将描述实现 MutableCollection 的所有写操作。 有关 ListMap 可用的更多特定操作,请分别参见 List 相关操作与 Map 相关操作。

** 添加元素**

  • 要将单个元素添加到列表或集合,请使用 add() 函数。指定的对象将添加到集合的末尾。
  • addAll() 将参数对象的每个元素添加到列表或集合中。
  • 你还可以使用 plus 运算符 - plusAssign (+=) 添加元素。 当应用于可变集合时,+= 将第二个操作数(一个元素或另一个集合)追加到集合的末尾。
//第一种
val numbers = mutableListOf(1, 2, 3, 4)
numbers.add(5)
println(numbers)
//第三种
val numbers = mutableListOf("one", "two")
numbers += "three"
println(numbers)
numbers += listOf("four", "five")    
println(numbers)

27、删除元素

若要从可变集合中移除元素,请使用 remove() 函数。 remove() 接受元素值,并删除该值的一个匹配项。

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

要一次删除多个元素,有以下函数:

  • removeAll() 移除参数集合中存在的所有元素。 或者,你可以用谓词作为参数来调用它;在这种情况下,函数移除谓词产生 true 的所有元素。
  • retainAll()removeAll() 相反:它移除除参数集合中的元素之外的所有元素。 当与谓词一起使用时,它只留下与之匹配的元素。
  • clear() 从列表中移除所有元素并将其置空。

从集合中移除元素的另一种方法是使用 minusAssign (-=) ——原地修改版的 minus 操作符。 minus 操作符。 第二个参数可以是元素类型的单个实例或另一个集合。 右边是单个元素时,-= 会移除它的第一个匹配项。 反过来,如果它是一个集合,那么它的所有元素的每次出现都会删除。 例如,如果列表包含重复的元素,它们将被同时删除。 第二个操作数可以包含集合中不存在的元素。这些元素不会影响操作的执行。

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

你可能感兴趣的:(Kotlin集合使用)