带你初识kotlin(五)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28898075/article/details/90767624

介绍

集合是大多数编程语言的常见概念通常包含相同类型的一些(数目也可以为零)对象。集合中的对象称为元素条目

集合类型

Kotlin标准库提供了基本集合类型的实现:集合,列表和映射。 一对接口代表每种集合类型:

  • read-only interface that provides operations for accessing collection elements.
  • mutable interface that extends the corresponding read-only interface with write operations: adding, removing, and updating its elements.
  1. List是一个有序集合,可以通过索引访问元素 (反映其位置的整数)。 元素可以在列表中出现多次。 list就像是是一个句子:它是一组单词,它们的顺序很重要,它们可以重复。
  2. Set是一系列唯一元素。 它反映了集合的数学抽象:一组没有重复的对象。 通常,集合元素的顺序没有意义。 例如,字母表是一组字母。
  3. Map(或dictionary)是一组键值对。 键是唯一的,每个键都映射到一个值。 值可以是重复的。 映射对于存储对象之间的逻辑连接很有用,例如,员工的ID和位置。

下面是kotlin接口的结构图

Collection

Collection 是集合层次结构的根。 此接口表示只读集合的常见行为:检索大小,检查项目成员资格等。 集合继承自Iterable 接口,该接口定义迭代元素的操作。 您可以使用Collection作为适用于不同集合类型的函数的参数。 对于更具体的情况,请使用Collection的继承者:List和Set。

fun printAll(strings: Collection<String>) {
        for(s in strings) print("$s ")
        println()
    }

fun main() {
    val stringList = listOf("one", "two", "one")
    printAll(stringList)

    val stringSet = setOf("one", "two", "three")
    printAll(stringSet)
}

运行结果:

one two one
one two three

MutableCollection是一个具有写操作的Collection,例如add和remove。

fun List<String>.getShortWordsTo(shortWords: MutableList<String>, maxLength: Int) {
    this.filterTo(shortWords) { it.length <= maxLength}
    // throwing away the articles
    val articles = setOf("a", "A", "an", "An", "the", "The")
    shortWords -= articles
}

fun main() {
    val words = "A long time ago in a galaxy far far away".split(" ")
    val shortWords = mutableListOf<String>()
    words.getShortWordsTo(shortWords, 3)
    println(shortWords)
}

运行结果:

[ago, in, far, far]

List

List 以指定的顺序存储元素,并提供对它们的索引访问。 索引从 第一个元素(0)开始到最后一个元素lastIndex(list.size - 1)。列表元素(包括空值)可以重复:列表可以包含任意数量的相等对象或单个对象的出现。 如果两个列表在相同位置具有相同的大小和结构相同的元素,则认为它们是相等的。

扫描二维码关注公众号,回复: 6540990 查看本文章
val bob = Person("Bob", 31)
val people = listOf<Person>(Person("Adam", 20), bob, bob)
val people2 = listOf<Person>(Person("Adam", 20), Person("Bob", 31), bob)
println(people == people2) //true
bob.age = 32
println(people == people2) //false

mutableList是一个具有特定于列表的写操作的List,例如,用于在特定位置添加或删除元素。

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

结果:

[0, 5, 4, 3]

如我们所见,在某些方面,列表与数组非常相似。 但是,有一个重要的区别:数组的大小是在初始化时定义的,永远不会改变; 反过来,列表没有预定义的大小; 写操作:添加,更新或删除元素,可以更改列表的大小。在Kotlin中,List的默认实现是ArrayList,您可以将其视为可调整大小的数组。

Set

Set存储唯一的元素, 他们的顺序通常是不确定的。 null元素也是唯一的就,Set只能包含一个null。 如果它们具有相同的大小,并且对于集合中的每个元素,在另一个集合中存在相等的元素,则两个集合相等。

val numbers = setOf(1, 2, 3, 4)
println("Number of elements: ${numbers.size}")
if (numbers.contains(1)) println("1 is in the set")

val numbersBackwards = setOf(4, 3, 2, 1)
println("The sets are equal: ${numbers == numbersBackwards}")

结果:

Number of elements: 4
1 is in the set
The sets are equal: true

MutableSet是一个带有来自MutableCollection的写操作的Set。

Set 的默认实现 是 LinkedHashSet保留元素插入的顺序。 因此,依赖于顺序的函数(例如first()或last())会在这些集合上返回可预测的结果。

val numbers = setOf(1, 2, 3, 4)  // LinkedHashSet is the default implementation
val numbersBackwards = setOf(4, 3, 2, 1)

println(numbers.first() == numbersBackwards.first())  //false
println(numbers.first() == numbersBackwards.last())      //true

另一种实现HashSet ,对元素顺序没有任何说明,因此在其上调用这些函数会返回不可预测的结果。 但是,HashSet存储相同数量的元素需要较少的内存。

Map

Map <K,V>不是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") // same as previous

结果:

All keys: [key1, key2, key3, key4]
All values: [1, 2, 3, 1]
Value by key “key2”: 2
The value 1 is in the map
The value 1 is in the map

无论对顺序如何,包含相等对的两个映射都是相等的

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)    
val anotherMap = mapOf("key2" to 2, "key1" to 1, "key4" to 1, "key3" to 3)

println("The maps are equal: ${numbersMap == anotherMap}") //true

MutableMap是一个带有Map写操作的Map,例如,您可以添加新的键值对或更新与给定键关联的值。

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

println(numbersMap) //{one=11, two=2, three=3}

与Set一样, LinkedHashMap是Map的默认实现 - 在迭代Map时保留元素插入的顺序。 反过来,另一种实现HashMap 对元素顺序没有任何说明。

构造集合

1.由元素构造

创建集合的最常用方法是使用标准库函数 listOf (),setOf (),mutableListOf (),mutableSetOf ()。 如果以逗号分隔的集合元素列表作为参数,则编译器会自动检测元素类型。 创建空集合时,请明确指定类型。map也是如此,用mapOf()和mutableMapOf()函数。 map的键和值作为Pair对象传递(通常使用infix函数to创建)。

val numbersSet = setOf("one", "two", "three", "four")
val emptySet = mutableSetOf<String>()
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)

请注意,to表示法会创建一个短生命的Pair对象,因此建议仅在性能不重要时才使用它。 为避免过多的内存使用,请使用其他方法。 例如可以创建mutableMap并使用写入操作填充它。 apply()函数可以帮助保持初始化流畅。

val numbersMap = mutableMapOf<String, String>().apply { this["one"] = "1"; this["two"] = "2" }

2.空集合

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

val empty = emptyList<String>()

3.list初始化函数

对于list,有一个构造函数,它接受列表大小和初始化函数两个参数,该函数根据索引定义元素值。

val doubled = List(3, { it * 2 })  // or MutableList if you want to change its content later
println(doubled) //[0, 2, 4]

4.具体类构造函数

要创建具体的类型集合(例如ArrayList或LinkedList),可以使用这些类型的可用构造函数。 类似的构造函数可用于Set和Map的实现。

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

5.复制

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

集合复制函数如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}")   //Copy size: 3

//readOnlyCopyList.add(4)             // compilation error
println("Read-only copy size: ${copyList.size}")//Read-only copy size: 3

或者,可以创建对同一集合实例的新引用。 使用现有集合初始化集合变量时,将创建新引用。 因此,当通过引用更改集合实例时,更改将反映在其所有引用中。

val sourceList = mutableListOf(1, 2, 3)
val referenceList = sourceList
referenceList.add(4)
println("Source size: ${sourceList.size}")//Source size: 4

迭代器

对于遍历集合元素,Kotlin标准库支持常用的迭代器机制 - 对象提供顺序访问元素而不暴露集合的底层结构。 当您需要逐个处理集合的所有元素(例如,打印值或对它们进行类似更新)时,迭代器非常有用。

通过调用iterator()函数,可以获取Iterable <T>接口的继承者的迭代器,包括SetList。 获得迭代器后,它指向集合的第一个元素; 调用next()函数返回此元素并将迭代器位置移动到以下元素(如果存在)。 一旦迭代器通过最后一个元素,它就不能再用于检索元素; 也不能将其重置为任何先前的位置。 要再次遍历集合,请创建一个新的迭代器。

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

}

另一种通过Iterable集合的方法是众所周知的for循环。 在集合上使用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()实现。 此外,ListIterator使用函数nextIndex()previousIndex()提供有关元素索引的信息。

能够在两个方向上进行迭代,意味着ListIterator在到达最后一个元素后仍然可以使用。

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()}")
}
Iterating backwards:
Index: 3, value: four
Index: 2, value: three
Index: 1, value: two
Index: 0, value: one

可变迭代器MutableIterator

对于MutableIterator而言,MutableIterator使用元素移除函数remove()扩展Iterator。 因此,您可以在迭代时从集合中删除元素。

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

mutableIterator.next()
mutableIterator.remove()    
println("After removal: $numbers")//After removal: [two, three, four]

除了删除元素之外,MutableListIterator还可以在迭代列表时插入和替换元素。

val numbers = mutableListOf("one", "four", "four") 
val mutableListIterator = numbers.listIterator()

mutableListIterator.next()
mutableListIterator.add("two")
mutableListIterator.next()
mutableListIterator.set("three")   
println(numbers)//[one, two, three, four]

序列

序列提供与Iterable相同的功能,但实现了多步骤收集处理的另一种方法。

构造

sequenceOf函数

调用sequenceOf函数,将元素列为其参数。

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

Iterable.asSequence()

如果已经有了Iterable对象(such as a List or a Set),可以通过asSequence()创建

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

函数generateSequence()

函数作为参数调用generateSequence()。您可以将第一个元素指定为显式值或函数调用的结果。 当提供的函数返回null时,序列生成停止。 因此,下面示例中的序列是无限的。

val oddNumbers = generateSequence(1) { it + 2 } // `it` is the previous element
println(oddNumbers.take(5).toList())
//println(oddNumbers.count())     // error: the sequence is infinite

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)

结果:

filter: The
filter: quick
filter: brown
filter: fox
filter: jumps
filter: over
filter: the
filter: lazy
filter: dog
length: 5
length: 5
length: 5
length: 4
length: 4
Lengths of first 4 words longer than 3 chars:
[5, 5, 5, 4]

filter()和map()函数的执行顺序与它们在代码中显示的顺序相同。 首先,您会看到filter:所有元素,然后是length:过滤后剩余的元素,然后是最后两行的输出。 这是列表处理的方式:

Sequence

val words = "The quick brown fox jumps over the lazy dog".split(" ")
//convert the List to a Sequence
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")
// terminal operation: obtaining the result as a List
println(lengthsSequence.toList())

Lengths of first 4 words longer than 3 chars
filter: The
filter: quick
length: 5
filter: brown
length: 5
filter: fox
filter: jumps
length: 5
filter: over
length: 4
[5, 5, 5, 4]

输出显示仅在构建结果列表时调用filter()和map()函数。 因此,您首先看到文本行“Lengths of ..”然后开始序列处理。 请注意,对于filter后留下的元素,map在filter下一个元素之前执行。 当结果大小达到4时,处理停止,因为它是(4)可以返回的最大可能大小。

序列处理如下:

猜你喜欢

转载自blog.csdn.net/qq_28898075/article/details/90767624