2.Kotlin_集合_note

本文深入探讨了Kotlin中的集合类型,包括List、Set和Map的实现与操作。介绍了创建、修改和遍历集合的方法,如ArrayList、LinkedHashSet、LinkedList、HashSet和LinkedHashMap。讲解了迭代器、序列、区间数列的概念与操作,以及过滤、转换、排序等集合操作。此外,还涵盖了集合操作中的成员函数和扩展函数,以及集合的转换、过滤、分组和排序等高级用法。
摘要由CSDN通过智能技术生成

List 是一个有序集合,可通过索引(反映元素位置的整数)访问元素。元素可以在 list 中出现多次。列
Set 是唯一元素的集合。它反映了集合(set)的数学抽象:一组无重复的对象。一般来说 set 中元素的顺序并不重要。
Map(或者字典)是一组键值对。键是唯一的,每个键都刚好映射到一个值。值可以重复。map 对于存储对象之间的逻辑连接非常有用,

注意:

1.更改可变集合不需要必须用 var 定义的变量:写操作修改同一个可变集合对象,因此引用不会改变

[Collection]是集合层次结构的根。此接口表示一个只读集合的共同行为:检索大小、检测是否为成员等等。 Collection 继承自 Iterable <T> 接口,它定义了迭代元素的操作。

[MutableCollection]是一个具有写操作的 Collection 接口,

在 Kotlin 中,List 的默认实现是 [ArrayList],可以将其视为可调整大小的数组

Set的默认实现 - [LinkedHashSet] – 保留元素插入的顺序。 因此,依赖于顺序的函数,例如 first()last(),会在这些 set 上返回可预测的结果。
另一种实现方式 – HashSet – 不声明元素的顺序,所以在它上面调用这些函数会返回不可预测的结果。但是,HashSet 只需要较少的内存来存储相同数量的元素

Map 的默认实现 – [LinkedHashMap] 迭代 Map 时保留元素插入的顺序。 反之,另一种实现 – HashMap – 不声明元素的顺序

1.创建集合

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

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

    //空集合list
    val list1 = listOf<String>()
    //固定大小集合list
    val list2 = listOf<String>("1","2")
    //可变大小集合list
    val list3 = mutableListOf<String>("1","2")
    
        //空set
    val set1 = setOf<String>()
    //固定set
    val set2 = setOf<String>("1","2")
    //可变大小set
    val set3 = mutableSetOf<String>("1","2")

    //空set
    val map1 = mapOf<String,String>()
    val map2 = mapOf<String,String>("1" to "A")
    //可变map
    val map3 = mutableMapOf<String,String>()

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

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

2 集合类型

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

Collection interfaces hierarchy

3 空集、初始化集合

emptyList()、emptySet() 与 emptyMap()。

list初始化

val doubled = List(3, { it * 2 })  // 如果你想操作这个集合,应使用 MutableList
println(doubled)
//具体类型的构造函数
val linkedList = LinkedList<String>(listOf("one", "two", "three"))
val presizedSet = HashSet<Int>(32)

复制
创建与现有集合具有相同元素的集合,可以使用复制操作

在特定时刻通过集合复制函数,例如toList()toMutableList()toSet() 等等。这些方法可以创建新的集合对象。

val sourceList = mutableListOf(1, 2, 3)
val copyList = sourceList.toMutableList()
val readOnlyCopyList = sourceList.toList()
sourceList.add(4)

转换为其他类型

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

更多:filter map mapIndexed

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


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

[3, 6, 9]
[0, 2, 6]


//associateWith 关联生成map
val numbers = listOf("one", "two", "three", "four")
println(numbers.associateWith { it.length })

{one=3, two=3, three=5, four=4}

4 迭代器Iterator

对于遍历集合元素, Kotlin 标准库支持 迭代器 的常用机制——对象可按顺序提供对元素的访问权限,而不会暴露集合的底层结构

Iterable 接口的继承者(包括 SetList)可以通过调用 iterator() 函数获得迭代器

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

**List 迭代器**

val numbers = listOf("one", "two", "three", "four")
val listIterator = numbers.listIterator()
while (listIterator.hasNext()) listIterator.next()

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

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

mutableIterator.next()
mutableIterator.remove()
mutableListIterator.add("two")
mutableListIterator.next()
mutableListIterator.set("three")

可变迭代器 MutableIterator

MutableIterator 来扩展 Iterator 使其具有元素删除函数 remove() 、add() set()

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

mutableIterator.next()
mutableIterator.remove()
mutableListIterator.set("three")
mutableListIterator.add("two")
println("After removal: $numbers")

5.区间 数列

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

//包含头尾值
if (i in 1..4) {  // 等同于 1 <= i && i <= 4
    print(i)
}

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

//downTo 反向迭代
for (i in 4 downTo 1) print(i)

// step 函数
for (i in 1..8 step 2) print(i)
//until 函数 算头不算尾
for (i in 1 until 10) {       // i in [1, 10), 10被排除
    print(i)
}

区间

要为类创建一个区间,请在区间起始值上调用 rangeTo() 函数,并提供结束值作为参数。 rangeTo() 通常以操作符 .. 形式调用。

class Version(val major: Int, val minor: Int): Comparable<Version> {
    override fun compareTo(other: Version): Int {
        if (this.major != other.major) {
            return this.major - other.major
        }
        return this.minor - other.minor
    }
}

fun main() {
    val versionRange = Version(1, 11)..Version(1, 30)
    println(Version(0, 9) in versionRange)
    println(Version(1, 20) in versionRange)
}

数列

如上个示例所示,整数类型的区间(例如 IntLongChar)可视为等差数列。 在 Kotlin 中,这些数列由特殊类型定义:IntProgressionLongProgressionCharProgression

数列具有三个基本属性:first 元素、last 元素和一个非零的 step

for (int i = first; i <= last; i += step) {
  // ……
}
for (i in 1..10) print(i)

数列的 last 元素是这样计算的:

  • 对于正步长:不大于结束值且满足 (last - first) % step == 0 的最大值。
  • 对于负步长:不小于结束值且满足 (last - first) % step == 0 的最小值。

6.序列

除集合外 还有一种容器 Sequenec, 序列提供与 Iterable 相同的函数,但实现另一种方法来进行多步骤集合处理。当 Iterable 的处理包含多个步骤时,它们会优先执行:每个处理步骤完成并返回其结果——中间集合。 在此集合上执行以下步骤。反过来,序列的多步处理在可能的情况下会延迟执行:仅当请求整个处理链的结果时才进行实际计算。

1.1 元素

val n = sequenecof("one","two")

1.2 Iterable

如果已经有一个iterable对象,可以调用asSequence()

val num = listof("one","two")
val numsequ = num.asSequnce();

1.3 函数???

通过使用计算其元素的函数来构建序列。要基于函数构建序列,请以该函数作为参数调用 generateSequence()。 (可选)可以将第一个元素指定为显式值或函数调用的结果。 当提供的函数返回 null 时,序列生成停止。,以下示例中的序列是无限的

//首次1执行,返回的结果+2再次执行
val oddNumbers = generateSequence(1) { it + 2 } // `it` 是上⼀个元素
println(oddNumbers.take(5).toList())//执行5次

//要使用 generateSequence() 创建有限序列,请提供一个函数,该函数在需要的最后一个元素之后返回 null
val oddNumbersLessThan10 = generateSequence(1) { if (it + 2 < 10) it + 2 else null }
println(oddNumbersLessThan10.count())

1.4 组块、

有一个函数可以逐个或按任意大小的组块生成序列元素——sequence() 函数。

此函数采用一个 lambda 表达式,其中包含 yield()yieldAll() 函数的调用。 它们将一个元素返回给序列使用者,并暂停 sequence() 的执行,直到使用者请求下一个元素。

yield() 使用单个元素作为参数;

yieldAll() 中可以采用 Iterable 对象、Iterable 或其他 Sequence

yieldAll()Sequence 参数可以是无限的。

当然,这样的调用必须是最后一个:之后的所有调用都永远不会执行。

    val oddNumbers = sequence {
        yield(1)
        yieldAll(listOf(3, 5))
        yieldAll(generateSequence(7) { it + 2 })
    }
    println(oddNumbers.take(5).toList())

1.5 序列操作

分为以下几类:

  • 无状态 操作不需要状态,并且可以独立处理每个元素,例如 map()filter()。 无状态操作还可能需要少量常数个状态来处理元素,例如 take()drop()
  • 有状态 操作需要大量状态,通常与序列中元素的数量成比例。

如果序列操作返回延迟生成的另一个序列,则称为 中间序列。 否则,该操作为 末端 操作。 末端操作的示例为 toList()sum()。只能通过末端操作才能检索序列元素。

序列可以多次迭代;但是,某些序列实现可能会约束自己仅迭代一次。其文档中特别提到了这一点

1.6 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)
//Sequence 执行同时满足多种条件的逻辑

  val words = "The quick brown fox jumps over the lazy dog".split(" ")
// 将列表转换为序列
  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")
// 末端操作:以列表形式获取结果。
  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]

7.集合操作

1.扩展与成员函数

集合操作在标准库中以两种方式声明:集合接口的成员函数扩展函数

创建自己的集合接口实现时,必须实现其成员函数。 为了使新实现的创建更加容易,请使用标准库中集合接口的框架实现:AbstractCollectionAbstractListAbstractSetAbstractMap 及其相应可变抽象类。

其他集合操作被声明为扩展函数。这些是过滤、转换、排序和其他集合处理功能。

2 集合转换

2.1 map 映射

转换从另⼀个集合的元素上的函数结果创建⼀个集合

val numbers = setOf(1, 2, 3)
println(numbers.map { it * 3 })

2.2 zip 合拢

转换是根据两个集合中具有相同位置的元素构建配对,不是map形式

//zip() 返回 Pair 对象的列表( List )

val colors = listOf("red", "brown", "grey")
val animals = listOf("fox", "bear", "wolf")
println(colors zip animals)
2.3 关联 associateWith

关联 转换允许从集合元素和与其关联的某些值构建 Map

val numbers = listOf("one", "two", "three", "four")
println(numbers.associateWith { it.length })

结果:
{one=3, two=3, three=5, four=4}

2.4 打平 flatten

去除多层集合内部的层级

val numberSets = listOf(setOf(1, 2, 3), setOf(4, 5, 6), setOf(1, 2))
println(numberSets.flatten())
2.5 序列转换成字符串 joinToString()
val numbers = listOf("one", "two", "three", "four")
println(numbers)
println(numbers.joinToString())

3.集合过滤filter

在Kotlin中,过滤条件由 谓词 定义——接受一个集合元素并且返回布尔值的 lambda 表达式:true 说明给定元素与谓词匹配,false 则表示不匹配

1 按谓词过滤
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)

filterIndexed():使用元素在集合中的位置过滤

filterNot() 反向过滤

filterIsInstance() 返回给定类型的集合元素

val numbers = listOf(null, 1, "two", 3.0, "four")
println("All String elements in upper case:")
numbers.filterIsInstance<String>().forEach {
    println(it.toUpperCase())
}

filterNotNull()返回所有的非空元素

partition() 通过一个谓词过滤集合并且将不匹配的元素存放在一个单独的列表中

val numbers = listOf("one", "two", "three", "four")
//匹配的和不匹配的存入集合
val (match, rest) = numbers.partition { it.length > 3 }

println(match)
println(rest)

result:
[three, four]
[one, two]
2.检验谓词
  • 如果至少有一个元素匹配给定谓词,那么 any() 返回 true
  • 如果没有元素与给定谓词匹配,那么 none() 返回 true
  • 如果所有元素都匹配给定谓词,那么 all() 返回 true
  • 注意,在一个空集合上使用任何有效的谓词去调用 all() 都会返回 true 。这种行为在逻辑上被称为 vacuous truth
val numbers = listOf("one", "two", "three", "four")

println(numbers.any { it.endsWith("e") })
println(numbers.none { it.endsWith("a") })
println(numbers.all { it.endsWith("e") })

println(emptyList<Int>().all { it > 5 })   // vacuous truth
3. plusminus` 操作符
val numbers = listOf("one", "two", "three", "four")
//Plus 相当于累加
val plusList = numbers + "five"
//minus 去除
val minusList = numbers - listOf("three", "four")
println(plusList)
println(minusList)

[one, two, three, four, five]
[one, two]
4.分组

基本函数 groupBy() 使用一个 lambda 函数并返回一个 Map。 在此 Map 中,每个键都是 lambda 结果,而对应的值是返回此结果的元素 List。 例如,可以使用此函数将 String 列表按首字母分组。

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

println(numbers.groupBy { it.first().toUpperCase() })
println(numbers.groupBy(keySelector = { it.first() }, valueTransform = { it.toUpperCase() }))

{O=[one], T=[two, three], F=[four, five]}
{o=[ONE], t=[TWO, THREE], f=[FOUR, FIVE]}
5.取集合的一部分

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

[one, two, three]
[four, five, six]
[two, three, four, five, six]
[one]
Chunked 分块

要将集合分解为给定大小的“块”

fun main() {
    val numbers = (0..10).toList()
    //每3个元素一块数据
    println(numbers.chunked(3))
}

[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
windowed

可以检索给定大小的集合元素中所有可能区间。windowed() 返回从每个集合元素开始的元素区间(窗口

val numbers = listOf("one", "two", "three", "four", "five")    
println(numbers.windowed(2))

step 定义两个相邻窗口的第一个元素之间的距离

partialWindows 包含从集合末尾的元素开始的较小的窗口

val numbers = (1..10).toList()
println(numbers.windowed(3, step = 2, partialWindows = true))
println(numbers.windowed(3) { it.sum() })

result:
[[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9], [9, 10]]
[6, 9, 12, 15, 18, 21, 24, 27]
6 取单个元素
// elementAt(index) 按下标取
val numbers = linkedSetOf("one", "two", "three", "four", "five")
println(numbers.elementAt(3))

//函数 first() 和 last() 按照条件获取
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.first { it.length > 3 })
println(numbers.last { it.startsWith("f") })

random() //函数 随机取
contains() //函数 是否存在

val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.elementAtOrNull(5))
println(numbers.elementAtOrElse(5) { index -> "The value for index $index is undefined"})
7 集合排序

类似Java里对象之间可以比较,比较就可以排序。可以继承compareable,重写方法compareTo

class Version(val major: Int, val minor: Int): Comparable<Version> {
    override fun compareTo(other: Version): Int {
        if (this.major != other.major) {
            return this.major - other.major
        } else if (this.minor != other.minor) {
            return this.minor - other.minor
        } else return 0
    }
}

fun main() {
    println(Version(1, 2) > Version(1, 3))
    println(Version(2, 0) > Version(1, 5))
}

//如需为类型定义自定义顺序,可以为其创建一个 Comparator。 Comparator 包含 compare() 函数:它接受一个类的两个实例并返回它们之间比较的整数结果。

val lengthComparator = Comparator { str1: String, str2: String -> str1.length - str2.length }
println(listOf("aaa", "bb", "c").sortedWith(lengthComparator))

Comparator 的一种比较简短的方式是标准库中的 compareBy() 函数

println(listOf("aaa", "bb", "c").sortedWith(compareBy { it.length }))

基本的函数

sorted() 升序

sortedDescending() 降序

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

asReversed() 反向函数

shuffled() 函数 随机产生一个新的list

8.list
9. set

查找交集、并集或差集。

要将两个集合合并为一个(并集),可使用 union() 函数。

要查找两个集合中都存在的元素(交集),请使用 intersect()

要查找另一个集合中不存在的集合元素(差集),请使用 subtract()

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]
10.map
val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
//根据key 去value
println(numbersMap.get("one"))
//另一种方式
println(numbersMap["one"])

println(numbersMap.getOrDefault("four", 10))
println(numbersMap["five"])               // null
//numbersMap.getValue("six")
  • getOrElse() 与 list 的工作方式相同:对于不存在的键,其值由给定的 lambda 表达式返回。
  • getOrDefault() 如果找不到键,则返回指定的默认值。

keys 是 Map 中所有键的集合, values 是 Map 中所有值的集合。

val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap.keys)
println(numbersMap.values)
4.1过滤
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
//根据filter过滤符合条件的数据
val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10}
println(filteredMap)

// filterKeys() 和 filterValues() 也可以通过两种形式过滤
4.2plusminus 操作
val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
//累加map 集合数据,以pair形式添加
println(numbersMap + Pair("four", 4))
//如果存在key,会进行value的覆盖
println(numbersMap + Pair("one", 10))
//可以接收map形式的数据
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 中使用 plusAssign+=)与 minusAssign-=)运算符的详细信息

4.3 增删改查

put

putall() 它的参数可以是 Map 或一组 PairIterableSequenceArray

+= 追加map数据

-= 移除map 数据

[] 设置新的数据

val numbersMap = mutableMapOf("one" to 1, "two" to 2)
numbersMap["three"] = 3     // 调用 numbersMap.set("three", 3)
numbersMap += mapOf("four" to 4, "five" to 5)
numbersMap -= "four" //根据key移除数据
println(numbersMap)

Remove()

val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3, "threeAgain" to 3)
numbersMap.keys.remove("one")//根据key 移除
println(numbersMap)
numbersMap.values.remove(3) //根据value 移除
println(numbersMap)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值