Kotlin - 集合 Collection(List、Set)

本文主要介绍Kotlin中集合Collection里的List和Set。阐述了集合的概念,包括继承关系、集合区别和类型协变;说明了List和Set的创建特点,如List有序可重复,Set无序不可重复;还提及了集合操作符,如转换、增删、获取等,最后提到了MutableList。

一、概念

1.1 继承关系

只读接口提供访问元素的操作,可变接口通过扩展只读接口提供变更元素的操作。

1.2 集合区别

元素不可变(只读)元素可变(增删改)
有序(有索引,元素可以重复)List<E>MutableList<E>
无序(无索引,元素不可重复)Set<E>MutableSet<E>
键值对(key具有唯一性)Map<K, V>MutableMap<K, V>

1.3 集合类型的协变

当一个集合赋值给另一个集合,或者可变集合与不可变集合互转的时候,如果集合类型不相同,子类可以赋值给父类。例如  List<Son> 可以赋值给 List<Father>,List<Son>可以 .toMutableList() 转为 List<Father>。

1.4 更高效的处理元素

在集合上链式调用多个操作(如 map + filter + flatMap)时,会产生中间集合,带来额外内存开销。若操作较复杂或数据量较大,推荐使用 asSequence() 转为惰性序列,以减少中间产物,提升性能。详见:序列Sequence

二、创建

2.1 List

元素是有序的,可以重复,因为该类型具备索引。底层使用的是ArrayList。

由元素构造

public inline fun <T> listOf(): List<T> = emptyList()

public inline fun <T> mutableListOf(): MutableList<T> = ArrayList()

创建空集合。

public fun <T> listOf(vararg elements: T): List<T>

public fun <T> mutableListOf(vararg elements: T): MutableList<T>

通过指定元素创建集合。

空集合

public fun <T> emptyList(): List<T>

创建空List。

工厂函数

public inline fun <T> List(size: Int, init: (index: Int) -> T): List<T>

public inline fun <T> MutableList(size: Int, init: (index: Int) -> T): MutableList<T>

参数size是指定大小, 参数init是每个元素的初始化方式。

构建器函数

public inline fun <E> buildList(builderAction: MutableList<E>.() -> Unit): List<E>

public inline fun <E> buildList(capacity: Int, @BuilderInference builderAction: MutableList<E>.() -> Unit): List<E>

参数initialCapacity是指定大小,参数builderAction是每个元素的初始化方式。作用域中调用的是 MutableList 的方法,最后返回的是一个 List。

具体类型的集合

public inline fun <T> arrayListOf(): ArrayList<T> = ArrayList()
public fun <T> arrayListOf(vararg elements: T): ArrayList<T>

Kotlin有自己包装过的ArrayList(不推荐,Kotlin的List底层就是由它实现的)。

public LinkedList()
public LinkedList(Collection<? extends E> c)

通过 Java 构造函数创建 LinkedList。

避免装箱开销

public fun intListOf(): IntList = EmptyIntList

public inline fun mutableIntListOf(): MutableIntList = MutableIntList()

public fun emptyIntList(): IntList = EmptyIntList

空集合。
public fun intListOf(vararg elements: Int): IntList
public inline fun mutableIntListOf(vararg elements: Int): MutableIntList

通过指定元素创建集合。
public inline fun buildIntList(builderAction: MutableIntList.() -> Unit): IntList
public inline fun buildIntList(initialCapacity: Int, builderAction: MutableIntList.() -> Unit): IntList

构建器函数。

非线程安全,且遍历中修改可能引发问题,总之别用就行。同理还有 Long、Double、Float。

val list1 = listOf(1,"哈哈",false)        //自动类型推断
val list2 = listOf<String>("你","我","他")        //声明确定类型
val list3 = buildList {
    add(1)
    add(2)
    add(3)
}

val linkedList1 = LinkedList<Int>(listOf(1,2,3))    //类型是 LinkedList<Int>
val linkedList2 = LinkedList(listOf(1,2,3)) //类型是  LinkedList<Int!>

2.2 Set

元素是无序的,不可以重复(任意两个元素 hashCode() 和 equals() 都不相等),存入和取出的顺序不一定相同。底层使用的是LinkedHashSet,当元素个数 N<3,初始容量为 N+1当元素个数 N<最大值/2+1,初始容量为 N+N/3,否则初始容量为 2147483647。

由元素构造

public inline fun <T> setOf(): Set<T> = emptySet()

public inline fun <T> mutableSetOf(): MutableSet<T> = LinkedHashSet()

创建空集合。

空集合

public fun <T> emptySet(): Set<T> = EmptySet

创建空Set。

构建器函数public inline fun <E> buildSet(@BuilderInference builderAction: MutableSet<E>.() -> Unit): Set<E>
public inline fun <E> buildSet(capacity: Int, @BuilderInference builderAction: MutableSet<E>.() -> Unit): Set<E>
具体类型的集合public inline fun <T> linkedSetOf(): LinkedHashSet<T> = LinkedHashSet()
public fun <T> linkedSetOf(vararg elements: T): LinkedHashSet<T>
public inline fun <T> hashSetOf(): HashSet<T> = HashSet()
public fun <T> hashSetOf(vararg elements: T): HashSet<T>
public fun <T> sortedSetOf(vararg elements: T): java.util.TreeSet<T>
public fun <T> sortedSetOf(comparator: Comparator<in T>, vararg elements: T): java.util.TreeSet<T>
val ss = mutableSetOf (1,3,5,7 )
ss + 9        // [1,3,5,7,9]
ss - listOf (1,3)        // [5,7]

2.3 集合字面量 Collection Literals

参考文章

v2.4.0-Bare2 引入,目前处于实验性。20260610

        通过方括号简洁创建集合,编译器会把方括号转换为对目标类型伴生对象上 operator fun of() 方法的调用。默认创建 List 类型,MutableList、Set、MutableSet 需要显示声明属性类型,不能把目标类型设成 Java 定义的集合类型。

  • Map 字面量:["key": 1] 目前还不存在。三个原因:Java 互操作痛点、装箱性能,以及 Map.Entry 是接口带来的尴尬。语法空间会先保留,也许未来再交付。
  • Tuple 字面量:Pair 和 Triple 不能通过方括号触达,部分原因是 operator fun of() 的形状无法在单个 vararg 中表达异构类型。
  • 没有期望类型的空字面量:val x = [] 会编译失败,原因和 emptyList() 返回 List<T> 而不是 List<Nothing> 类似。

2.3.1 基本使用

// 显式类型声明
val shapes: MutableList<String> = ["triangle", "square", "circle"]
// 无声明默认创建 List
val fruit = ["apple", "banana", "cherry"]

if (countryCode in ["US", "CA", "MX"]) {
    ...
}

2.3.2 自定义容器

这个机制是开放的,任何类型只要在伴生对象上提供格式正确的 operator fun of() 就可以使用方括号。

目前处于实验性

kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xcollection-literals")
    }
}

这两个 of 重载是合法的,因为它们只在参数数量上不同,而且 vararg rest 前面的每个参数都和 rest 本身拥有相同类型。这样写,能强迫你必须创建一个非空的容器,因为你不能 [] 这么写,这是个非常值得学习的小技巧。两个重载必须返回相同类型,并且拥有相同可见性。

// 定义
class NonEmptyList<T> private constructor(
    val head: T,
    val tail: List<T>,
) {
    val size: Int get() = 1 + tail.size
    fun toList(): List<T> = listOf(head) + tail

    companion object {
        operator fun <T> of(first: T): NonEmptyList<T> =
            NonEmptyList(first, emptyList())

        operator fun <T> of(first: T, vararg rest: T): NonEmptyList<T> =
            NonEmptyList(first, rest.toList())
    }
}
// 使用
val onboarding: NonEmptyList<OnboardingStep> = [
    OnboardingStep.Welcome,
    OnboardingStep.PermissionsRequest,
    OnboardingStep.AccountLinking,
]

当期望类型本身也支持方括号时,可以嵌套使用。在矩阵式或网格式数据中,这种写法能带来可读性提升。

// 定义
class DoubleMatrix(vararg val rows: Row) {
    companion object {
        operator fun of(vararg rows: Row) = DoubleMatrix(*rows)
    }

}
class Row(vararg val elements: Double) {
    companion object {
        operator fun of(vararg elements: Double) = Row(*elements)
    }
}
// 使用
val identityMatrix: DoubleMatrix = [
    [1.0, 0.0, 0.0],
    [0.0, 1.0, 0.0],
    [0.0, 0.0, 1.0],
]

三、转换

toList ()

toMutableList ()

toSet ()

toMutableSet ()

转换为 List 集合,有序

转换为 Set 集合,去重

转换为 Mutable***元素可变集合

associate ()

associateBy ()

转换为 Map

to***Array ()转换为基本类型数组

四、合并

plus (元素/数组/集合/序列)

minus (元素/数组/集合/序列)
plusElement (元素)

numusElement (元素)

plus(T):List<T>

plus(Iterable<T>):List<T>

plus(Array<out T>):List<T>

plus(Sequence<T>):List<T>

往集合中添加一个元素/数组/集合/序列,返回一个新集合不会修改原集合,推荐使用操作符 “+”

minus(T):List<T>

minus(Iterable<T>):List<T>

minus(Array<out T>):List<T>

minus(Sequence<T>):List<T>

往集合中删除一个元素/数组/集合/序列,返回一个新集合,推荐使用操作符 “-”

plusElement(T):List<T>

同上,底层使用的 plus(T)

minusElement(T):List<T>

同上,底层使用的 minus(T)

val list1 = listOf(1,2,3)
val list2 = listOf(7,8)
val list3 = list1 + 4     //返回的是一个新集合,不会修改原集合list1,[1,2,3,4]
val list4 = list1.plus(list2)//返回的是一个新集合,不会修改原集合list1,[1,2,3,7,8]

五、获取

5.1 根据索引获取元素

get (索引)

getOrElse (索引,默认值)

getOrNull (索引)

elementAt (索引)

elementAtOrElse (索引,默认值)

elementAtOrNull (索引)

get(Int):T

获取该索引位置上的元素,没有则报错,推荐使用运算符 [ ]

getOrElse(Int,Int -> T):T

获取该索引位置上的元素,没有则返回默认值

getOrNull(int):T?

获取该索引位置上的元素,没有则返回 null

elementAt(Int):T

获取该索引位置上的元素,没有则报错,推荐使用运算符 [ ]

elementAtOrElse(Int,Int -> T):T

获取该索引位置上的元素,没有则返回默认值

elementAtOrNull(Int):T?

获取该索引位置上的元素,没有则返回 null

5.2 根据元素获取索引

indexOf (元素)

indexOfFrist (条件)

indexOfLast (条件)

lastIndexOf (元素)

indexOf(T):Int

获取该元素在List中对应的索引,没有则返回-1

indexOfFrist(T -> Boolean):Int

获取第一个符合条件的元素索引,没有则返回-1

indexOfLast(T -> Boolean):Int

获取最后一个符合条件的元素索引,没有则返回-1

lastIndexOf (T):Int

获取该元素最后一次出现的索引,没有则返回-1

5.3 首尾元素

frist ()

frist (predicate)

fristOrNull ()

fristOrNull (predicate)

last ()

last (predicate)

lastOrNull ()

lastorNull (predicate)

find ()

findLast ()

frist():T

获取第一个元素,没有则报错

frist(T ->Boolean):T

获取第一个符合条件的元素,没有则抛异常

fristOrNull():T?

获取第一个元素,没有则返回 null

fristOrNull(T ->Boolean):T?

获取符合条件的第一个元素,没有则返回 null

last():T

获取最后一个元素,没有则报错

last(T -> Boolean):T

获取最后一个符合条件的元素,没有则抛异常

lastOrNull():T?

获取最后一个元素,没有则返回 null

lastOrNull(T -> Boolean):T?

获取符合条件的最后一个元素,没有则返回 null

find(T -> Boolean):T

同理 frist(),获取第一个符合条件的元素,没有则抛异常

同理 lastOrNull (),获取符合条件的最后一个元素,没有则返回 null

5.4 唯一元素

single ()

single (predicate)

singleOrNull ()

single()

集合只能且必须包含一个元素,并返回该元素,否则报错

single(T -> Boolean):T

集合只能且必须包含一个符合条件的元素,并返回该元素,否则报错

singOrNull():T?

集合只能且必须包含一个符合条件的元素,并返回该元素,否则返回 null

5.5 平均值

average ()

average ():T

获取所有元素的平均值(元素之和/元素数量,仅限数值类型)

5.6 最值

min ()

minBy (function(索引)) : T

max ()

maxBy (function(索引)) : T

min():T?

返回集合中最小值的元素,空集返回 null

minBy(T -> R):T?

根据条件,返回集合中最小值的元素,空集返回 null。比较的是运算后的R,但返回的是元素T

max():T?

返回集合中最大值的元素,空集返回 null

maxBy(T -> R):T?

根据条件,返回集合中最小值的元素,空集返回 null。比较的是运算后的R,但返回的是元素T

六、查询

count ()

count (predicate)

count():Int

集合中元素的个数

count(T -> Boolean):Int

集合中满足条件的元素个数

min ()

minBy (function(索引)) : T

max ()

maxBy (function(索引)) : T

min():T?

返回集合中最小值的元素,空集返回 null

minBy(T -> R):T?

根据条件,返回集合中最小值的元素,空集返回 null。比较的是运算后的R,但返回的是元素T

max():T?

返回集合中最大值的元素,空集返回 null

maxBy(T -> R):T?

根据条件,返回集合中最小值的元素,空集返回 null。比较的是运算后的R,但返回的是元素T

contains (元素)

containsAll (集合)

contains(T):Boolean

集合中是否包含该元素,包含返回true

contains(Collection):Boolean

集合中是否包含该子集,包含返回true

any ()

any (条件)

all (条件)

none ()

none (条件)

any():Boolean

集合中是否至少有一个元素

any(T -> Boolean):Boolean

集合中是否至少有一个元素满足条件

all(T -> Boolean):Boolean

集合中是否所有元素都满足条件

none():Boolean

集合中是否没有元素

none(T -> Boolean):Boolean

集合中是否没有元素满足条件

6.1 元素个数(集合大小)

size

count ()

count (条件)

count():Int

集合中元素的个数

count(T -> Boolean):Int

集合中满足条件的元素个数

6.2 是否包含某元素

contains (元素)

containsAll (集合)

contains(T):Boolean

集合中是否包含该元素,包含返回true

contains(Collection):Boolean

集合中是否包含该子集,包含返回true

6.3 满足条件

6.3.1 是否有元素满足条件

any ()

any (条件)

any():Boolean

集合中是否至少有一个元素

any(T -> Boolean):Boolean

集合中是否至少有一个元素满足条件

6.3.2 是否元素全部满足条件

all (条件)

all(T -> Boolean):Boolean

集合中是否所有元素都满足条件

6.3.3 是否没有元素满足条件

none ()

none (条件)

none():Boolean

集合中是否没有元素

none(T -> Boolean):Boolean

集合中是否没有元素满足条件

6.4 是否有序

v2.4.0 开始支持。如果元素按指定顺序排列,或者元素少于两个,它们将返回 true,否则返回 false。这些函数在遇到无序对时会立即停止,这使得它们对大型输入非常高效。

isSorted()

isSortedDescending()

isSortedWith(比较器)

isSortedBy(条件)

isSortedByDescending(条件)

public fun <T : Comparable<T>> Iterable<T>.isSorted(): Boolean

public fun <T : Comparable<T>> Iterable<T>.isSortedDescending(): Boolean
public fun <T> Iterable<T>.isSortedWith(comparator: Comparator<in T>): Boolean
public inline fun <T, R : Comparable<R>> Iterable<T>.isSortedBy(selector: (T) -> R?): Boolean
public inline fun <T, R : Comparable<R>> Iterable<T>.isSortedByDescending(selector: (T) -> R?): Boolean

七、子集

7.1 从区间截取

slice (区间)

slice (集合)

slice(IntRange):List<T>

截取该索引区间的元素,返回一个子List

slice(Iterable<Int>):List<T>

返回一个子List,所包含的 element 是传入 Iterable 的 element 当作 index 对应的 element

7.2 从头或从尾开始截取

take (数量)

takeLast (数量)

takeWhile (predicate)

takeLastWhile (predicate)

take(Int):List<T>

截取前 N 个元素,返回一个子集合,N=0返回空集,N>size返回该集合,N<0报错

takeLast(Int):List<T>

截取后 N 个元素,返回一个子集合,N=0返回空集,N>size返回该集合,N<0报错

takeWhile(T -> Boolean):List<T>

正序,返回一个满足条件元素的子集合,遇到不满足条件就停止

takeLastWhile(T -> Boolean):List<T>

倒序,返回一个满足条件元素的子集合,遇到不满足条件就停止

7.3 从头或从尾开始去除

drop (数量)

dropLast (数量)

dropWhile (predicate)

dropLastWhile (predicate)

drop(Int):List<T>

去除前 N 个元素,返回一个包含剩下元素的子集合,N=0返回该集合,N>size返回空集,N<0报错

dropLast(Int):List<T>

去除后 N 个元素,返回一个包含剩下元素的子集合,N=0返回该集合,N>size返回空集,N<0报错

dropWhile(T -> Boolean):List<T>

正序,去除满足条件的元素,返回一个包含剩下元素的子集合,遇到不满足条件就停止

dropLastWhile(T -> Boolean):List<T>

倒序,去除满足条件的元素,返回一个包含剩下元素的子集合,遇到不满足条件就停止

7.4 去重

distinct ()

distinctBy (function)

distinct():List<T>

去除重复元素(会保留第一次出现的)。

distinctBy(T -> K):List<T>

去除集合中的重复给定元素(会保留第一次出现的)。

7.5 过滤

filter (predicate)

filterIndexed (predicate(索引,元素))

filterNot (predicate)

filterNotNull (predicate)

filterTo (子集合,predicate)

filter(T -> Boolean):List<T>

返回一个包含满足条件元素的子集合

同上,多了索引可使用

filterNot(T -> Boolean):List<T>

返回一个包含不满足条件元素的子集合???????

filterNotNull(T -> Boolean):List<T>

返回一个不包含null元素的子集合???????

filterTo(MutableCollection,T -> Boolean):MutableCollection

用传入的子集合 MutableCollection 去装满足条件的 element,并返回子集合

八、排序

8.1 条件排序

sorted ()

sortedDescending ()

sortedBy (function)

sortedDescendingBy (function(元素))

sorted():List<T>

将集合中的元素按照自然排序进行升序排列

sortedDescending():List<T>

将集合中的元素按照自然排序进行降序排列

sortedBy(T -> R?):Unit

根据函数对集合中的 element 进行计算,按结果进行升序排列,结果类型要实现Comparable

sortedDescendingBy(T -> R?):Unit

根据函数对集合中的 element 进行计算,按结果进行降序排列,结果类型要实现Comparable

8.2 反转顺序

reversed ()

reversed():List<T>

反转集合中的元素,返回一个新集合

九、运算

9.1 累加

sumOf ( 元素 -> 累加值 )

sumOf(T -> Int):Int

对元素挨个进行累加计算,初始值为0

9.2 规约

reduce ( (累加值,下一个元素) -> 累加值 )

reduceRight ( (下一个元素,累加值) -> 累加值 )

fold ( 初始值,(累加值,下一个元素) -> 累加值 )

foldRight ( 初始值, (下一个元素, 累加值) -> 累加值 )

reduce( (S,T) -> S):S

根据给定的函数,正序对元素挨个进行运算

reduceRight( (T,S) -> S):S

根据给定的函数,倒序对元素挨个进行运算

fold(R,(R,T) -> R):R

带初始值的 reduce

foldRight(R,(T,R) -> R):R

带初始值的 reduceRight

十、映射(新集)

10.1 转成 List

map (function(元素))

mapIndexed (function(索引,元素)->新值)

mapNotNull (function(元素))

map(T -> R):List<R>

通过函数对元素进行运算,返回一个包含运算后元素的新集合。

T元素,R运算后的值

mapIndexed( (Int,T) -> R):List<R>

通过函数对元素进行运算,返回一个包含运算后元素的新集合,多了一个索引可使用

通过函数对元素进行运算,返回一个包含运算后元素的新集合,会去掉null元素

10.2 转成 List<List>

windowed()
chunked()
val numbers = (1..5).toList()
println(numbers.windowed(3)) // [[1,2,3],[2,3,4],[3,4,5]]
println(numbers.chunked(2))  // [[1,2],[3,4],[5]]

10.3 转成 Map

groupBy (T -> 键): Map(键, List<T>)

groupBy (T -> 键,T -> 值): Map<键,值>

groupBy (T -> 值): Grouping<T,值>

groupBy(T -> K):Map<K,list<T> >

对 element 进行运算,结果当作 key,相同结果的 element 为一组 List 当作 Value

groupBy (T -> K,T -> V): Map<K,V>

对 element 进行运算,第一个运算结果当作 Key,第二个运算结果当作 Value

groupBy(T -> K): Grouping<T,K>

10.4 转成 List<Pair>

zip (集合2): List<Pair<集合1元素, 集合2元素>>

zip(Iterable<R>):List<Pait<T,R>>

对两个集合进行配对,相同 index 的两个 element 存入 Pair,作为返回的新List 的 element

10.5 转成 Pair

partition (predicate): Pair<List1包含所有满足条件的元素,List2包含所有不满足条件的元素>

partition(T -> Boolean):Pair<List<T>,List<T>>

根据条件,将集合拆成2个子集合组成的Pair,满足条件的在左边

十一、遍历

11.1 遍历

forEach (元素 -> Unit)

forEach(T -> Unit):Unit

遍历

forEachIndexed ( (索引,元素) -> Unit )

forEachIndexed( (Int,T) -> Unit):Unit

带索引遍历,Int是索引,T是元素

onEach()对每个元素执行操作
(1..5).map { it * 2}.onEach { println(it) }.toList()

11.2 展平

flatten ()

flatMap (function(元素))

遍历集合中的元素,元素包含子元素也遍历。

flatMap(T -> Iterable<R>):List<R>

展平后再进行映射。

val nested = listOf(listOf(1,2), listOf(3,4))
val flat = nested.flatten() // [1,2,3,4]

val flatDoubled = nested.flatMap { it.map { it*2 } } // [2,4,6,8]

十二、MutableList

toList ()转换为 List 元素不可变集合

add (元素)

add (索引,元素)

addAll (子集合)

addAll (索引,子集合)

add(E):Boolean

在集合尾部添加新元素,成功则返回true

add(Int,E):Boolean

往该索引位置上插入新元素,索引不存在则报错

addAll(Collection<E>):Boolean

添加子集合,成功则返回true

addAll(Int,Collection<E>):Boolean

往该索引位置上插入子集合,成功则返回true

remove (元素)

removeAt (索引)

removeAll (子集合)

remove(E):Boolean

删除集合中第一次出现的该元素,成功则返回true

removeAt(Int):E

删除该索引位置上的元素,索引不存在则报错

removeAll(Collection<E>):Boolean

删除子集合,成功则返回true

set (索引,元素)

set(Int,E):E

对该索引上的元素赋值

clear ()

clear():Unit

清空集合中的元素

retainAll (另一个集合)

retainAll(Collection<E>):Boolean

取交集:只保留两个集合都有的元素,成功则返回true

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值