Kotlin详见集合与操作符

[TOC]

前言

kotlin的集合分为不可变集合和可变集合

Kotlin 的 List<out T> 只提供只读操作如 sizeget等的接口。和 Java 类似,它继承自 Collection<T> 进而继承自 Iterable<T>。改变 list 的方法是由 MutableList<T> 加入的。这一模式同样适用于 Set<out T>/MutableSet<T>Map<K, out V>/MutableMap<K, V>。详见下表

不可变 可变
Iterable MutableIterable
Collection MutableCollection
List MutableList
Set MutableSet
Map MutableMap

ListSet的基本用法

val numbers: MutableList<Int> = mutableListOf(1, 2, 3)
val readOnlyView: List<Int> = numbers
println(numbers)        // 输出 "[1, 2, 3]"
numbers.add(4)
println(readOnlyView)   // 输出 "[1, 2, 3, 4]"
readOnlyView.clear()    // -> 不能编译

val strings = hashSetOf("a", "b", "c", "c")
assert(strings.size == 3)

总数操作符

any

只要有一个元素符合判断条件,则返回true

val list = listOf(1, 2, 3, 4, 5, 6)
list.any { it % 2 == 0} // true
list.any { it > 10 } // false

all

只有全部的元素符合判断条件,则返回true

val list = listOf(1, 2, 3, 4, 5, 6)
list.all { it < 10 } // true
list.all { it % 2 == 0} // false

count

返回符合判断条件的元素总数

val list = listOf(1, 2, 3, 4, 5, 6)
list.count { it % 2 == 0 } // 3

fold

给定一个初始值,在初始值的基础上,通过给定的函数来累计所有元素。

val list = listOf(1, 2, 3, 4, 5, 6)
list.fold(4) { total, next -> total + next } // 4+1+2+3+4+5+6 = 25
list.fold(4) { total, next -> total * next } // 4*1*2*3*4*5*6 = 2880

foldRight

fold一样,只是顺序是从最后一项到第一项

val list = listOf(1, 2, 3, 4, 5, 6)
list.foldRight(4) { total, next -> total + next } // 25

forEach

遍历的所有的元素,并执行给定的操作

val list = listOf(1, 2, 3, 4, 5, 6)
list.forEach { println(it) }

forEachIndexed

forEach类似,但是我们同时可以得到元素的index

val list = listOf(1, 2, 3, 4, 5, 6)
list.forEachIndexed { (index, value) -> println("position $index contains a $value") }

max/min

返回最大/最小的一项,如果没有则返回null

val list = listOf(1, 2, 3, 4, 5, 6)
list.max() // 6
list.min() // 1

maxBy/minBy

根据给定的函数返回最大/最小的一项,如果没有则返回null

val list = listOf(1, 2, 3, 4, 5, 6)
list.maxBy { -it } // 1
list.minBy { -it } // 6

none

如果没有任何元素与给定的函数匹配,则返回true

val list = listOf(1, 2, 3, 4, 5, 6)
list.none { it % 7 == 0 } // true

reduce

fold一样,但是没有一个初始值。通过给定的函数来累计所有元素

val list = listOf(1, 2, 3, 4, 5, 6)
list.reduce { total, next -> total + next } // 21

reduceRight

reduce一样,但是顺序是从最后一项到第一项

val list = listOf(1, 2, 3, 4, 5, 6)
list.reduceRight { total, next -> total + next } // 21

sum

返回所有元素的和

val list = listOf(1, 2, 3, 4, 5, 6)
list.sum() // 21

sumBy

返回所有元素通过给定的函数转换之后的数据总和

val list = listOf(1, 2, 3, 4, 5, 6)
list.sumBy { it % 2 } // 3
list.sumBy { it + 1 } // 27

过滤操作符

drop

返回包括去掉前n个元素的所有元素的列表

val list = listOf(1, 2, 3, 4, 5, 6)
list.drop(4) // listOf(5, 6)

dropWhile

这个函数有点难理解,我们需要结合一下源码来看:

public inline fun <T> Iterable<T>.dropWhile(predicate: (T) -> Boolean): List<T> {
    var yielding = false
    val list = ArrayList<T>()
    for (item in this)
        if (yielding)
            list.add(item)
        else if (!predicate(item)) {
            list.add(item)
            yielding = true
        }
    return list
}

调用dropWhile时,先遍历集合,如果集合中的元素不符合predicate函数的规则,则从当前元素开始,所有元素依次添加到新集合list并返回,如果集合中的元素都符合规则,则一个都不添加。我们以下面的例子来分析:

val list1 = listOf(1, 2, 3, 4, 5, 6)
list1.dropWhile { it < 3 } // listOf(3, 4, 5, 6)

在上面的例子中,我们定义的函数规则是当前元素要小于3{it < 3},当集合遍历到3时,因为3是不小于3的,不符合函数的规则,所以从3开始,往后的元素都被添加到了新集合中。

再来看一个例子,我们把集合中的6放到最前面

val list2 = listOf(6, 1, 2, 3, 4, 5)
list2.dropWhile { it < 3} // listOf(6, 1, 2, 3, 4, 5)

遍历集合时,因为第一个元素是6,不符合{it < 3},所要6及之后的元素都被添加到了新集合中

dropLastWhile

返回根据给定函数从最后一项开始去掉指定元素的列表

val list = listOf(1, 2, 3, 4, 5, 6)
list.dropLastWhile { it > 4 } // listOf(1, 2, 3, 4)

filter

返回符合给定条件的元素

val list = listOf(1, 2, 3, 4, 5, 6)
list.filter { it % 2 == 0 } // listOf(2, 4, 6)
list.filter { it < 3 } // listOf(1, 2)

filterNot

返回所有不符合给定函数条件的元素

val list = listOf(1, 2, 3, 4, 5, 6)
list.filterNot { it % 2 == 0} // listOf(1, 3, 5)

filterNotNull

返回集合中非null的函数

val list = listOf(1, 2, 3, 4, 5, null)
println(list.filterNotNull()) // listOf[1, 2, 3, 4, 5]

slice

返回指定区域的元素

val list = listOf(1, 2, 3, 4, 5, 6)
list.slice(0..3) // listOf(1, 2, 3, 4)
list.slice(listOf(1, 3, 4)) // listOf(2, 4, 5)

(0..3):表示取出第0个到第3个之间的元素

listOf(1, 3, 4):表示取出下标为1、3、4的元素

take

返回从第一个开始的n个元素(返回前n个元素)

val list = listOf(1, 2, 3, 4, 5, 6)
list.take(2) // listOf[1, 2]

takeLast

返回从最后一个开始的n个元素(返回后n个元素)

val list = listOf(1, 2, 3, 4, 5, 6)
list.take(2) // listOf[5, 6]

takeWhile

返回从第一个开始符合给定函数条件的元素

val list = listOf(1, 2, 3, 4, 5, 6)
list.takeWhile { it < 3 } // listOf[1, 2]

映射操作符

flatMap

遍历所有的元素,为每个元素创建一个集合,最后把所有的集合放在一个集合中。

什么意思呢,就是你可以把每一个元素转化成一个新的list,最后这些list会合并成一个大的list。我们通过代码来分析:

val list = listOf(1, 2, 3, 4, 5, 6)
list.flatMap { listOf('a' + it) } // listOf(b, c, d, e, f, g)

上面的例子中,我们通过函数listOf('a'+ it)把每一个元素都转换成了新的list。因为我们有6个元素,所以会生成6个list(listOf(b)、listOf(c)、listOf(d)、listOf(e)、listOf(f)和listOf(g)),最后会遍历这6个list,把这6个list中的每一项添加到一个新的list中。当然你也可以为listOf('a' + it)添加多个元素,看下面的例子:

val list = listOf(1, 2, 3, 4, 5, 6)
list.flatMap { listOf(it, 'a' + it) } // listOf(1, b, 2, c, 3, d, 4, e, 5, f, 6, g)

groupBy

返回一个根据给定函数分组后的map,把函数的返回值作为key,符合条件的所有元素作为value

val list = listOf(1, 2, 3, 4, 5, 6)
// 返回为 mapOf("odd" to listOf(1, 3, 5), "even" to listOf(2, 4, 6)}
list.groupBy { if (it % 2 ==0) "even" else "odd" } 

map

返回一个每一个元素根据给定的函数转换所组成的List(把元素列表中的每一项进行相应计算或转成其它你想要的任何格式)。

把元素中的每一项乘2:

val list = listOf(1, 2, 3, 4, 5, 6)
list.map { it * 2 } // listOf(2, 4, 6, 8, 10, 12)

把元素中的每一项转成字母:

val list = listOf(1, 2, 3, 4, 5, 6)
list.map { 'a' + it } // listOf(b, c, d, e, f, g)

mapIndexed

map一样,但是我们可以同时得到元素的index

val list = listOf(1, 2, 3, 4, 5, 6)
list.mapIndexed { index, it -> index + it } // listOf(1, 3, 5, 7, 9, 11)

mapNotNull

map一样,但是会过滤掉为null的元素

class Person(val name: String? = null)
val list = listOf(Person(), Person("Alice"))
// map
list.map { it.name } // listOf(null, "Alice")
// mapNotNull
list.mapNotNull { it.name } // listOf("Alice")

元素操作符

contains

如果的元素可以在集合中找到,则返回true

val list = listOf(1, 2, 3, 4, 5, 6)
list.contains(2) // true

elementAt

返回给定index对应的元素,如果index数组越界则会抛出IndexOutOfBoundsException

val list = listOf(1, 2, 3, 4, 5, 6)
list.elementAt(1) // 2

elementAtOrElse

返回给定index对应的元素,如果index数组越界则会返回给定函数的返回值,函数中的参数为给定的index。如下图所示:it为传入的10

val list = listOf(1, 2, 3, 4, 5, 6)
list.elementAtOrElse(10, { 2 * it }) // 20

elementAtOrNull

返回给定index对应的元素,如果index数组越界则会返回null

val list = listOf(1, 2, 3, 4, 5, 6)
list.elementAtOrNull(10) // null

first

返回符合给定函数条件的第一个元素,如果没有符合抛出java.util.NoSuchElementException

val list = listOf(1, 2, 3, 4, 5, 6)
list.first() // 1
list.first { it % 2 == 0 } // 2

firstOrNull

返回符合给定函数条件的第一个元素,如果没有符合则返回null

val list = listOf(1, 2, 3, 4, 5, 6)
list.firstOrNull() // 1
list.firstOrNull { it % 7 == 0 }) // null

indexOf

返回指定元素的第一个index,如果不存在,则返回-1

val list = listOf(1, 2, 3, 4, 5, 6)
list.indexOf(4) // 3

indexOfFirst

返回第一个符合给定函数条件的元素的index,如果没有符合则返回-1

val list = listOf(1, 2, 3, 4, 5, 6)
list.indexOfFirst { it % 2 == 0 } // 1

indexOfLast

返回最后一个符合给定函数条件的元素的index,如果没有符合则返回-1

val list = listOf(1, 2, 3, 4, 5, 6)
list.indexOfLast { it % 2 == 0 } // 5

last

返回符合给定函数条件的最后一个元素

val list = listOf(1, 2, 3, 4, 5, 6)
list.last { it % 2 == 0 } // 6

lastIndexOf

返回的指定元素的最后一个index,如果不存在,则返回-1

val list = listOf(1, 2, 3, 4, 5, 6)
list.lastIndexOf(2) // 1
list.lastIndexOf(7) // -1

single/singleOrNull

返回符合给定函数的单个元素,如果没有符合或者超过一个,single抛出异常,singleOrNull返回null

val list = listOf(1, 2, 3, 4, 5, 6)
list.single { it % 5 == 0 } // 5
list.single { it % 2 == 0 } // java.lang.IllegalArgumentException
list.singleOrNull { it % 2 == 0 } // null

生产操作符

partition

把一个集合通过给定的函数分为两个集合,符合条件的作为一个,不符合的作为另一个

val list = listOf(1, 2, 3, 4, 5, 6)
list.partition { it % 2 == 0 } // Pair(listOf(2, 4, 6), listOf(1, 3, 5))

plus

使用+号操作符把两个集合合并到一个集合中

val list = listOf(1, 2, 3, 4, 5, 6)
list + listOf(7, 8 ) // listOf(1, 2, 3, 4, 5, 6, 7, 8)

zip(返回值 List<Pair<T, R>>)

返回由Pair组成的List,每个Pair由两个集合中相同index的元素组成。这个返回的List的大小是由最小的那个集合决定

val list = listOf(1, 2, 3, 4, 5, 6)
list.zip(listOf(7, 8)) // listOf(Pair(1, 7), Pair(2, 8))

unzip

从包含Pair的List中生成包含List的Pair 。有点拗口,看代码

val list = listOf(Pair(5, 7), Pair(6, 8))
list.unzip() // Pair(listOf(5, 6), listOf(7, 8))

看上面的代码,还是有点难理解,我们需要结合源码来看

public fun <T, R> Iterable<Pair<T, R>>.unzip(): Pair<List<T>, List<R>> {
    val expectedSize = collectionSizeOrDefault(10)
    val listT = ArrayList<T>(expectedSize)
    val listR = ArrayList<R>(expectedSize)
    for (pair in this) {
        listT.add(pair.first)
        listR.add(pair.second)
    }
    return listT to listR
}

unzip方法中,会定义两个集合,一个集合会添加list元素Pair(5,7), Pair(6,8)first,出就是5、6,另一个集合会添加second,也就是7、8

顺序操作符

reversed

返回一个倒序的list

val list = listOf(1, 2, 3, 4, 5, 6)
list.reversed() // listOf(6, 5, 4, 3, 2, 1)

sorted

把list进行生序排列

val list = listOf(1, 3, 2, 5, 4, 6)
list.sorted() // listOf(1, 2, 3, 4, 5, 6)

sortedBy

把不符合条件的元素按照在集合中之前的顺序放在集合的最前面,把符合条件的元素依次放在后面

val list = listOf(7, 6, 3, 2, 5, 4, 1)
list.sortedBy { it > 2 } // listOf(2, 1, 7, 6, 3, 5, 4)

看代码,因为2,1不符合条件,所以把2,1按之前的顺序放到最前面,7,6,3,5,4仿照之前的顺序依次放到后面

sortedDescending

把list进行降序排列

val list = listOf(7, 4, 3, 1, 5, 6, 2)
list.sortedDescending() // listOf(7, 6, 5, 4, 3, 2, 1)

sortedByDescending

sortedBy类似,只不过是把符合条件的放在集合的前面,不符合的放在集合的后面

val list = listOf(7, 4, 3, 1, 5, 6, 2)
list.sortedByDescending { it > 3 } // listOf(7, 4, 5, 6, 3, 1, 2)

参考: 《kotlin-for-android-developers》《kotlin in action》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容