集合
集合
一个集合通常包含多个相同类型的对象(这个数字也可能为零)
以下集合类型与 Kotlin 相关:
- List是一个有序集合,可以通过索引访问元素 - 反映其位置的整数。元素可以在列表中出现多次。列表的一个例子是电话号码:它是一组数字,它们的顺序很重要,它们可以重复。
- Set是独特元素的集合。它反映了集合的数学抽象:一组没有重复的对象。通常,集合元素的顺序没有意义。例如,彩票上的数字形成一个集合:它们是唯一的,它们的顺序并不重要。
- Map(或字典)是一组键值对。键是唯一的,每个键都映射到一个值。这些值可以是重复的。地图对于存储对象之间的逻辑连接很有用,例如,员工的 ID 和他们的职位。
Kotlin 标准库提供基本集合类型的实现:集合、列表和映射。一对接口代表每种集合类型:
- 一个只读接口,提供访问集合元素的操作。
- 一个可变接口,它通过写操作扩展了相应的只读接口:添加、删除和更新其元素。
val numbers = mutableListOf("one", "two", "three", "four")
numbers.add("five") // 成功
println(numbers)
//numbers = mutableListOf("six", "seven") // 异常
Kotlin 集合接口的示意图:
Iterable : 迭代器
MutableIterable: 返回此序列元素的迭代器,该迭代器支持在迭代期间删除元素。
Collection : size,isEmpty(),contains(检查指定元素是否包含在此集合中。)containsAll,检查指定集合中的所有元素是否都包含在此集合中
MutableCollection:add,remove,addAll,removeAll,retainAll(仅保留此集合中包含在指定集合中的元素。)clear()
回报:
如果从集合中删除任何元素,则为 true;如果集合未被修改,则为 false。)
List:
- 父类继承 size,isEmpty(),contains(检查指定元素是否包含在此集合中。)containsAll,(检查指定集合中的所有元素是否都包含在此集合中)
- 子类特有 get,indexOf,lastIndexOf,listIterator(返回此列表中元素的列表迭代器(以正确的顺序)。)subList(集合截取,包头不包尾)
MutableList
- 父类继承:add,remove,addAll,removeAll,retainAll(仅保留此集合中包含在指定集合中的元素。)clear(),get,indexOf,lastIndexOf,listIterator(返回此列表中元素的列表迭代器(以正确的顺序)。)subList(集合截取,包头不包尾)
- 子类特有 removeAt
Set
- 父类继承 size,isEmpty(),contains(检查指定元素是否包含在此集合中。)containsAll(检查指定集合中的所有元素是否都包含在此集合中.)
MutableSet
父类继承:add,remove,addAll,removeAll,retainAll(仅保留此集合中包含在指定集合中的元素。)clear()
Map
size,isEmpty(),containsKey(key),containsValue(value),get(key),getOrDefault(key,defaultValue),
keys(返回此映射中所有键的只读 Set。)
values(返回此映射中所有值的只读集合。 请注意,此集合可能包含重复值。)
entries(返回此映射中所有键/值对的只读 Set。)
MutableMap
put(),remove(key),putAll(Map),clear()
remove(key,value) 仅当映射到指定值时才删除指定键的条目。
集合构造
创建集合的最常见方法是使用标准库函数listOf()、setOf()、mutableListOf()、mutableSetOf()。如果您提供以逗号分隔的集合元素列表作为参数,编译器会自动检测元素类型。创建空集合时,明确指定类型。
val numbersSet = setOf("one", "two", "three", "four")
val emptySet = mutableSetOf<String>()
这同样适用于具有 和 功能的mapOf()地图mutableMapOf()。地图的键和值作为对象传递Pair(通常使用中to缀函数创建)。
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)
to符号创建了一个短暂的Pair对象,因此建议您仅在性能不重要时使用它。为避免过度使用内存,请使用其他方法。例如,您可以创建一个可变映射并使用写入操作填充它。该apply()函数可以帮助在这里保持初始化流畅。
val numbersMap = mutableMapOf<String, String>().apply { this["one"] = "1"; this["two"] = "2" }
创建集合的另一种方法是调用构建器函数 - buildList()、buildSet()或buildMap()。他们创建一个新的、对应类型的可变集合,使用写操作填充它,并返回一个具有相同元素的只读集合:
val map = buildMap {
put("a", 1)
put("b", 0)
put("c", 4)
}
println(map) // {a=1, b=0, c=4}
空集合
还有用于创建不带任何元素的集合的函数:emptyList()、emptySet()和emptyMap()。创建空集合时,您应该指定集合将包含的元素类型。
具体类型构造函数
要创建具体的类型集合,例如ArrayListor LinkedList,您可以使用这些类型的可用构造函数。类似的构造函数可用于Set和的实现Map。
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"))
alice.name = "Alicia"
//sourceList[0] = Alicia copyList [0] = Alicia
//sourceList.size = 3 copyList.size = 2
这些函数也可用于将集合转换为其他类型,例如,从列表构建集合,反之亦然。
val sourceList = mutableListOf(1, 2, 3)
val copySet = sourceList.toMutableSet()
copySet.add(3)
copySet.add(4)
println(copySet)//[1, 2, 3, 4]
val sourceList = mutableListOf(1, 2, 3)
val referenceList = sourceList
referenceList.add(4)
println(sourceList)
println(referenceList)
println(sourceList === referenceList)
//[1, 2, 3, 4]
//[1, 2, 3, 4]
//true
可以通过对其他集合的各种操作来创建集合。例如,过滤列表会创建一个与过滤器匹配的新元素列表:
val numbers = listOf("one", "two", "three", "four")
val longerThan3 = numbers.filter { it.length > 3 }
println(longerThan3)
associateWith:将list转为map
val numbers = listOf("one", "two", "three", "four")
println(numbers.associateWith { it.length })
迭代器
用来遍历集合元素
val numbers = listOf("one", "two", "three", "four")
val numbersIterator = numbers.iterator()
while (numbersIterator.hasNext()) {
println(numbersIterator.next())
}
val numbers = listOf("one", "two", "three", "four")
for (item in numbers) {
println(item)
}
val numbers = listOf("one", "two", "three", "four")
numbers.forEach {
println(it)
}
List iterators
对于列表,有一个特殊的迭代器实现:ListIterator. 它支持双向迭代列表:向前和向后。
ListIterator.hasNext()。next() 向后.
listIterator.hasPrevious() previous()向前.
MutableIterator 可变迭代器
val numbers = mutableListOf("one", "four", "four")
val mutableListIterator = numbers.listIterator()
mutableListIterator.next()
mutableListIterator.add("two")
mutableListIterator.next()
mutableListIterator.set("three")
println(numbers)
收集操作概述
Kotlin 标准库提供了各种各样的函数来对集合执行操作。这包括简单的操作,例如获取或添加元素,以及更复杂的操作,包括搜索、排序、过滤、转换等。
常用操作
集合转换
map
非空判断
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 })
单独key操作
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
println(numbersMap.mapKeys { it.key.uppercase() })
println(numbersMap.mapValues { it.value + it.key.length })
zip
集合合并
val colors = listOf("red", "brown", "grey")
val animals = listOf("fox", "bear", "wolf")
println(colors zip animals) //[(red, fox), (brown, bear), (grey, wolf)]
val twoAnimals = listOf("fox", "bear")
println(colors.zip(twoAnimals))//[(red, fox), (brown, bear)]
list转map
基本关联函数associateWith()创建一个Map,其中原始集合的元素是键,值由给定的转换函数从它们产生。
val numbers = listOf("one", "two", "three", "four")
println(numbers.associateWith { it.length })
associateBy()创建一个Map,自定义key,值为list的值。
val numbers = listOf("one", "two", "three", "four")
println(numbers.associateBy { it.first().uppercaseChar() })
println(numbers.associateBy(keySelector = { it.first().uppercaseChar() }, valueTransform = { it.length }))
Flatten
将嵌套元素展开。
val numberSets = listOf(setOf(1, 2, 3), setOf(4, 5, 6), setOf(1, 2))
println(numberSets.flatten())
//[1, 2, 3, 4, 5, 6, 1, 2]
集合字符串展示
joinToString()和joinTo()
val numbers = listOf("one", "two", "three", "four")
println(numbers)//[one, two, three, four]
println(numbers.joinToString())//one, two, three, four
//添加字符
val listString = StringBuffer("The list of numbers: ")
numbers.joinTo(listString)
println(listString)//The list of numbers: one, two, three, four
构建自定义字符串表示,您可以在函数参数separator、prefix和中指定其参数postfix。生成的字符串将以 开头,以.prefix结尾postfix。将separator出现在除最后一个元素之外的每个元素之后。
val numbers = listOf("one", "two", "three", "four")
println(numbers.joinToString(separator = " | ", prefix = "start: ", postfix = ": end"))
//start: one | two | three | four: end
集合省略 limit :展示的位数。truncated:末尾省略。
val numbers = (1..100).toList()
println(numbers.joinToString(limit = 10, truncated = "<...>"))
//1, 2, 3, 4, 5, 6, 7, 8, 9, 10, <...>
Filter 过滤
val numbers = listOf("one", "two", "three", "four")
val longerThan3 = numbers.filter { it.length > 3 }
println(longerThan3)
//[three, four]
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}
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)//[two, four]
println(filteredNot)//[three, four]
Partition
match 返回过滤后的数据
rest 返回被删选掉的数据
val numbers = listOf("one", "two", "three", "four")
val (match, rest) = numbers.partition { it.length > 3 }
println(match)//[three, four]
println(rest)//[one, two]
- any()如果至少一个元素与给定的谓词匹配,则返回true。
- none() 如果没有任何元素与给定的谓词匹配,则返回true。
- all() 如果所有元素都匹配给定的谓词,则返回true。
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
any()并且none()也可以在没有谓词的情况下使用:在这种情况下,他们只是检查集合是否为空。
分组
- eachCount()计算每组中的元素。
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.groupBy { it.first().uppercase() })
println(numbers.groupBy(keySelector = { it.first() }, valueTransform = { it.uppercase() }))
//{O=[one], T=[two, three], F=[four, five]}
//{o=[ONE], t=[TWO, THREE], f=[FOUR, FIVE]}
Slice 集合分割
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.slice(1..3))//截取1-3
println(numbers.slice(0..4 step 2))//截取0-4 并跳过2
println(numbers.slice(setOf(3, 5, 0))) //取 3, 5,0
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.take(3))//取前三
println(numbers.takeLast(3))//取后三
println(numbers.drop(1))//去除前1
println(numbers.dropLast(5))//去除后5
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.takeWhile { !it.startsWith('f') })//从0开始到首字母为f
println(numbers.takeLastWhile { it != "three" })//从最后开始到== three
println(numbers.dropWhile { it.length == 3 })//去除从0开始到第一个长度等于3的。
println(numbers.dropLastWhile { it.contains('i') })//从末尾开始去除包含i的。
Chunked 分块
val numbers = (0..13).toList()
println(numbers.chunked(3))
//[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13]]
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.windowed(3))
//[[one, two, three], [two, three, four], [three, four, five]]
val numbers = (1..10).toList()
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]
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]
检索单个元素
- elementAt() 获取特定位置元素
- first() 获取第一个
- last() 获取最后一个
first()后接lamda表达添加条件
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.first { it.length > 3 })
println(numbers.last { it.startsWith("f") })
- elementAtOrNull() 获取特定位置元素 没有返回null
- elementAtOrElse()获取特定位置元素 没有返回Else
- random() 随机获取集合内数据
- contains() 是否包含
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() 是否为空。
Ordering
在 Kotlin 中,可以通过多种方式定义对象的顺序。
自然秩序是为Comparable接口的实现而定义的。当没有指定其他顺序时,使用自然顺序对它们进行排序。
- 数值类型使用传统的数值顺序:1大于0;-3.4f大于-5f,以此类推。
- Char并String使用字典顺序:b大于a;world大于hello。
**要为用户定义的类型定义自然顺序,请将该类型设为Comparable. 这需要实现该compareTo()功能。compareTo()必须将另一个相同类型的对象作为参数,并返回一个整数值,显示哪个对象更大:
**
- 正值表示接收对象更大。
- 负值表明它小于参数。
- 零表示对象相等。
使用Comparator()自定义排序规则
val lengthComparator = Comparator { str1: String, str2: String -> str2.length - str1.length }
println(listOf("aaa", "bb", "c","fffff").sortedWith(lengthComparator))
compareBy()接受一个 lambda 函数,该函数从实例中生成一个Comparable值,并将自定义顺序定义为生成值的自然顺序。
println(listOf("aaa", "bb", "c").sortedWith(compareBy { it.length }))
//[c, bb, aaa]
sorted() 自然排序。
sortedBy() 根据自定义条件排序。
reversed() 集合反转。返回新集合。
asReversed() 返回同一集合反转数据。
val numbers = mutableListOf("one", "two", "three", "four")
val reversedNumbers = numbers.asReversed()
println(reversedNumbers)//[four, three, two, one]
numbers.add("five")
println(reversedNumbers)//[five, four, three, two, one]
shuffled() 已随机顺序返回一个包含集合元素的新集合-
Aggregate operations 聚合操作
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() and minByOrNull() 通过附加条件的最大值与最小值
- maxWithOrNull()并minWithOrNull()取一个Comparator对象并根据它返回最大或最小的元素Comparator。
- maxOfOrNull()并minOfOrNull()取一个选择器函数并返回选择器本身的最大或最小返回值。
- maxOfWithOrNull()并minOfWithOrNull()取一个Comparator对象并根据它返回最大或最小的选择器返回值Comparator。
- sumOf 值附加条件后在求和
val numbers = listOf(2, 4, 2, 2)
println(numbers.sumOf { it * 2 })
//20
reduce():sum:每次相加总数结果。element :数组元素。
fold(initial):initial:初始值,写0效果等同于reduce()。sum:每次相加总数结果。element :数组元素。
val numbers = listOf(5, 2, 10, 4)
val simpleSum = numbers.reduce { sum, element ->
sum + element
}
集合写操作
添加元素
addAll() 添加全部
val numbers = mutableListOf(1, 2, 3, 4)
numbers.add(5)
println(numbers)
removing()删除
val numbers = mutableListOf(1, 2, 3, 4, 3)
numbers.remove(3)
println(numbers)
removeAll()传入一个集合 删除集合内的所有元素。
retainAll() 保留符合条件的元素。
clear() 删除所有。
特定于列表的操作
- getOrElse()如果集合中不存在索引,则允许您提供计算要返回的默认值的函数。
- getOrNull()null作为默认值返回。
val numbers = listOf(1, 2, 3, 4)
println(numbers.get(0))
println(numbers[0])
//numbers.get(5) // exception!
println(numbers.getOrElse(5, {7})) // 7
检索部分列表
val numbers = (0..13).toList()
println(numbers.subList(3, 6))
//[3, 4, 5]
查找元素位置
- indexOf()返回等于列表中给定参数的元素的第一个索引。
- lastIndexOf()返回等于列表中给定参数的元素的最后一个索引。
- indexOfFirst()返回与谓词匹配的第一个元素的索引,-1或者如果没有这样的元素。
- indexOfLast()返回与谓词匹配的最后一个元素的索引,-1或者如果没有这样的元素。
二分搜索
binarySearch() 需要根据特定顺序对列表进行升序排序:自然或函数参数中提供的另一种顺序。否则,结果是未定义的。
要搜索排序列表中的元素,请调用binarySearch()将值作为参数传递的函数。如果存在这样的元素,则函数返回其索引;否则,它返回(-insertionPoint - 1)whereinsertionPoint是应该插入此元素的索引,以便列表保持排序。如果具有给定值的元素不止一个,则搜索可以返回它们的任何索引。
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
比较二分查找
当列表元素不是Comparable时,您应该提供一个Comparator在二分搜索中使用。列表必须根据 this 升序排列Comparator
val productList = listOf(
Product("WebStorm", 49.0),
Product("IOSCode", 99.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 }))
//2 先比较price,在比较name.
- add()
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() simply replaces all the collection elements with the specified value.
val numbers = mutableListOf(1, 2, 3, 4)
numbers.fill(3)
println(numbers)
- remove
val numbers = mutableListOf(1, 2, 3, 4, 3)
numbers.removeAt(1)
println(numbers)