kotlin集合高效使用

意大利 威尼斯

1、來了老弟?
2、映射为List: map{},mapIndexed{},mapNotNull{},mapIndexedNotNull{}

val numbers = setOf(1, 2, 3)

println(numbers.map { it * 3 })

//[3, 6, 9]

println(numbers.mapIndexed { idx, value -> value * idx })

//[0, 2, 6]

3、双路合并

(1)zip()将两个集合中具有相同位置的元素构建配对。

val list1 = listOf(1, 2, 3)

val list2 = listOf("a", "b", "c")

val list = list1.zip(list2)

println(list)

//[(1, a), (2, b), (3, c)]

val list3 = list1.zip(list2) { l1, l2 -> "${l1}----${l2}" }

println(list3)

//[1----a, 2----b, 3----c]

(2)反向转换unzip(),list.unzip()得到一个Pair对象

val numberPairs = listOf("one" to 1, "two" to 2, "three" to 3, "four" to 4)

println(numberPairs.unzip())

//([one, two, three, four], [1, 2, 3, 4])

4、关联

根据集合元素和与其关联的某些值构建 Map。

(1) Map associateWith() 。其中原始集合的元素是键,值来自给定的转换函数。 如果两个元素相等,则仅保留最后一个。

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

val map = numbers.associateWith { it.length }

println(map)

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

(2) associateBy()。 键来自给定的转换函数,原始集合中的元素是值。也可以使用keySelector和valueTransform设置键和值。两个元素相等,则仅保留最后一个。

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

println(numbers.associateBy { it.first().toUpperCase() })

//{O=one, T=three, F=four}

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

//{O=3, T=5, F=4}

(3)associate()。键和值都是根据集合元素生成的。associate() 会生成临时的 Pair 对象,这可能会影响性能。

data class FullName(val firstName: String, val lastName: String)

fun parseFullName(fullName: String): FullName {

    val nameParts = fullName.split(" ")

    if (nameParts.size == 2) {

        return FullName(nameParts[0], nameParts[1])

    } else throw Exception("Wrong name format")

}

val names = listOf("Alice Adams", "Brian Brown", "Clara Campbell")

println(names.associate { name -> parseFullName(name).let { it.lastName to it.firstName } })

//{Adams=Alice, Brown=Brian, Campbell=Clara}

5、打平

flatMap()可以打平集合中对象的某个类型为list的字段的值。

data class StringContainer(val values: List<String>)

val containers = listOf(

        StringContainer(listOf("one", "two", "three")),

        StringContainer(listOf("four", "five", "six")),

        StringContainer(listOf("seven", "eight"))

)

println(containers)

//[StringContainer(values=[one, two, three]), StringContainer(values=[four, five, six]), StringContainer(values=[seven, eight])]

println(containers.flatMap { it.values })

//[one, two, three, four, five, six, seven, eight]

//即可以打平集合中对象的某个类型为list的字段的值

6、字符串表示

(1)joinToString() 根据提供的参数从集合元素构建单个 String。

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

println(numbers)

//[one, two, three, four]

println(numbers.joinToString())

//one, two, three, four

println(numbers.joinToString("-", "开始", "结束"))

//开始one-two-three-four结束

println(numbers.joinToString("-", "开始", "结束", 3))

//开始one-two-three-...结束

println(numbers.joinToString("-", "开始", "结束", 3, "等等"))

//开始one-two-three-等等结束

println(numbers.joinToString("-", "开始", "结束", 3, "等等", { it -> it.toUpperCase() }))

//开始ONE-TWO-THREE-等等结束

(2)joinTo() 执行相同的操作,但将结果附加到给定的 Appendable (可追加的)对象。

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

val listString = StringBuffer("The list of numbers: ")

numbers.joinTo(listString, "-", "开始", "结束", 3, "等等", { it -> it.toUpperCase() })

println(listString)

//The list of numbers: 开始ONE-TWO-THREE-等等结束

7、过滤

(1)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}

(2)filterIndexed()。可以检查元素的索引和元素的值。

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

val filteredIdx = numbers.filterIndexed { index, value -> (index != 0) && (value.length < 5) }

println(filteredIdx)

//[two, four]

(3) filterNot()。使用否定条件来过滤集合。

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

val filteredNot = numbers.filterNot { it.length <= 3 }

println(filteredNot)

//[three, four]

(4)filterIsInstance<T>() 返回给定类型的集合元素。

val numbers = listOf(null, 1, "two", 3.0, "four")

println(numbers.filterIsInstance<String>())

//[two, four]

(5)filterNotNull() 返回所有的非空元素。在一个 List<T?> 上被调用时,filterNotNull() 返回一个 List<T: Any>。

val numbers = listOf(null, "one", "two", null)

println(numbers.filterNotNull())

//[one, two]

8、划分

partition() – 根据集合中元素的值进行过滤,并且返回一个Pair<List,List>。第一个list表示符合条件的集合;第二个list表示不符合条件的集合。

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

val (match, rest) = numbers.partition { it.length > 3 }

println(match)

//[three, four]

println(rest)

//[one, two]

9、集合元素检查

(1)

如果至少有一个元素匹配给定谓词,那么 any() 返回 true。

如果没有元素与给定谓词匹配,那么 none() 返回 true。

如果所有元素都匹配给定谓词,那么 all() 返回 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

println(emptyList<Int>().all { it > 5 })

//true

(2)当any() 和 none()不设置条件时, 它们只是用来检查集合是否为空。 如果集合中有元素(即使是null),any() 返回 true,否则返回 false;none() 则相反

10、集合加减:plus与minus

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

//集合加和,第二个操作数可以是集合,也可以是元素

val plusList = numbers + "five"

println(plusList)

//[one, two, three, three, four, five]

//如果第二个操作数是一个集合,那么移除其元素在原始集合中的 所有 出现。

val minusList1 = numbers - listOf("three")

println(minusList1)

//[one, two, four]

//如果第二个操作数是一个元素,那么 minus 移除其在原始集合中的 第一次 出现

val minusList2 = numbers - "three"

println(minusList2)

//[one, two, three, four]

11、分组

(1) groupBy()

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

//根据转换函数得到key,value来自于集合的元素

println(numbers.groupBy { it.first().toUpperCase() })

//{O=[one], T=[two, three], F=[four, five]}

//根据转换函数得到key,value来自于对原有集合元素的转换结果

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

//{O=[one], T=[two, three], F=[four, five]}

(2) grouping()

在分组后,对所有的分组进行一次操作。eachCount() 计算每个组中的元素。还有fold()、reduce()、aggregate()等。

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

println(numbers.groupingBy { it.first() }.eachCount())

//{o=1, t=2, f=2, s=1}

12、取集合的一部分

(1)slice() 返回给定索引处的集合元素列表。

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

println(numbers.slice(1..3))

//[two, three, four]

println(numbers.slice(0..4 step 2))

//[one, three, five]

println(numbers.slice(setOf(3, 5, 0)))

//[four, six, one]

(2)take和drop

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

//从头开始获取指定数量的元素

println(numbers.take(3))

//[one, two, three]

//从尾部开始获取指定数量的元素

println(numbers.takeLast(3))

//[four, five, six]

//从头开始去除给定数量的元素

println(numbers.drop(1))

//[two, three, four, five, six]

//从尾部开始去除给定数量的元素

println(numbers.dropLast(5))

//[one]

(3)takeWhile()和dropWhile()

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

//不停地获取元素,直到遇到使表达式为false的首个元素。如果首个集合元素便使表达式为false,则结果为空。

println(numbers.takeWhile { !it.startsWith('f') })

//[one, two, three]

//从尾部开始,如上

println(numbers.takeLastWhile { it != "three" })

//[four, five, six]

//不停地删除元素,直到遇到使表达式为false的首个元素,然后返回剩余的元素。如果首个集合元素便使表达式为false,则返回集合所有的元素。

println(numbers.dropWhile { it.length == 3 })

//[three, four, five, six]

//从尾部开始,如上

println(numbers.dropLastWhile { it.contains('i') })

//[one, two, three, four]

(4)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 = (0..13).toList()

//将集合切割成指定大小的子集后,对子集元素进行转换

println(numbers.chunked(3) { it.sum() })

//[3, 12, 21, 30, 25]

(5)windowed()

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

//检索指定大小的所有可能子集

println(numbers.windowed(3))

//[[one, two, three], [two, three, four], [three, four, five]]

//设置步长

println(numbers.windowed(3, 2))

//[[one, two, three], [three, four, five]]

//partialWindows为true时,即使剩余的元素数量小于窗口长度,也会返回结果

println(numbers.windowed(3, 2, true))

//[[one, two, three], [three, four, five], [five]]

//对得到的所有子集进行转换

println(numbers.windowed(3, 2, true, { list -> list.map { it.toUpperCase() } }))

//[[ONE, TWO, THREE], [THREE, FOUR, FIVE], [FIVE]]

(6)zipWithNext()

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

//从头开始,返回所有的相邻元素对(Pair)

println(numbers.zipWithNext())

//[(one, two), (two, three), (three, four), (four, five)]

//s1,s2即相邻元素对

println(numbers.zipWithNext { s1, s2 -> s1.length > s2.length })

13、取单个元素

(1)elementAt()获取指定索引处的元素

val str = linkedSetOf("one", "two", "three", "four", "five").elementAt(3)

(2)elementAtOrNull()

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

//越界后返回null

println(numbers.elementAtOrNull(5))

//null

(3)elementAtOrElse()

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

//越界后返回lambda表达式的结果

println(numbers.elementAtOrElse(5) { index -> "The value for index $index is undefined" })

//The value for index 5 is undefined

(4)first()和last()

first()和last()也可以根据表达式查找。但是如果没有查找到目标元素,将会抛出异常。用 firstOrNull() 和 lastOrNull()替代,如果没有找到,会返回null。

可以使用find() 代替 firstOrNull();使用 findLast() 代替 lastOrNull()

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

println(numbers.first { it.length > 3 })

//three

println(numbers.last { it.startsWith("f") })

//five

(5) random()

随机返回一个元素。对于空集合会抛出异常。可以使用randomOrNull()替代,会返回null。

14、排序

(1)sortedWith(comparator: Comparator<in T>)

//compareBy()可根据给定的lambda表达式返回Comparator

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

//[c, bb, aaa]

(2) sorted() 和 sortedDescending()

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

//自然升序

println(numbers.sorted())

//[four, one, three, two]

//自然降序

println(numbers.sortedDescending())

//[two, three, one, four]

(3) sortedBy(lambda表达式) 和 sortedByDescending(lambda表达式)

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

val sortedNumbers = numbers.sortedBy { it.length }

println(sortedNumbers)

//[one, two, four, three]

val sortedByLast = numbers.sortedByDescending { it.last() }

println(sortedByLast)

//[four, two, one, three]

(4)reversed()和asReversed()

var numbers = mutableListOf("one", "two", "three", "four")

//返回原有集合的倒序副本,且和原有集合没有关联

println(numbers.reversed())

//[four, three, two, one]

//返回原有集合的倒序视图,且和原有集合相关联。即改变原有的集合,已得到的倒序视图会发生改变。

val reversedNumbers = numbers.asReversed()

println(reversedNumbers)

//[four, three, two, one]

numbers.add("five")

println(reversedNumbers)

//[five, four, three, two, one]

(5)shuffled()

返回一个以随机顺序排列的含有原有集合元素的新list

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

println(numbers.shuffled())

15、聚合

(1)聚合操作如min()、max()、average()、sum()这些都只是对于数字类型的集合可用。count()计算集合中元素数量。

minBy{}、maxBy{}接收一个表达式;minWith{}、maxWith{}接收一个Comparator对象,可以由compareBy{}产生。

sumBy{}、sumByDouble{}接收一个表达式。前者对int类型的元素求和,并返回int。后者对Double类型的元素求和,并返回Double。

(2)fold()和reduce()。以及OrNull版本。

val numbers = listOf(5, 1, 3, 2)

//第一步的两个操作数分别是集合中第一个和第二个元素。(则第一个元素无法乘以2)

println(numbers.reduce { sum, element -> sum + element * 2 })

//17

//为sum设置了初始值。每一次的操作数都是sum和当前的集合元素。(可以保证每一个元素都乘以2)

println(numbers.fold(0) { sum, element -> sum + element * 2 })

//22

(3) reduceRight() 和 foldRight()从尾部开始进行计算。以及OrNull版本。

(4)foldIndexed()和reduceIndexed()将元素索引作为参数进行操作。以及OrNull版本。

val numbers = listOf(5, 2, 10, 4)

println(numbers.foldIndexed(0) { idx, sum, element -> if (idx % 2 == 0) sum + element else sum })

//15

println(numbers.reduceIndexed { idx, sum, element -> if (idx % 2 == 0) sum + element else sum })

//15

(5)reduceRightIndexed() 与 foldRightIndexed()从尾部开始进行计算。以及OrNull版本。

16、List操作

(1)getOrElse()、getOrNull()

val numbers = listOf(1, 2, 3, 4)

//越界时,返回null

println(numbers.getOrNull(5))

//越界时,返回表达式的结果,it等于index

println(numbers.getOrElse(6, { it }))

(2) indexOf() 返回元素第一个位置。 lastIndexOf() 返回元素最后一个位置。

(3)indexOfFirst() 和 indexOfLast() 可以接收一个表达式。

(4)二分查找 binarySearch()

要求该列表按照一定的顺序(自然排序或函数参数中提供的另一种排序)按升序排序过。

查询失败将返回 (-insertionPoint - 1),其中 insertionPoint 为应插入此元素的索引,以便列表保持排序。

如果存在多个目标元素返回其任一索引。

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

numbers.sort()

println(numbers)

//four, one, three, two]

println(numbers.binarySearch("two"))

// 3

println(numbers.binarySearch("z"))

// -5

println(numbers.binarySearch("two", 0, 2))

// -3

(5)通过Comparator使用二分查找

data class Product(val name: String, val price: Double)

val productList = listOf(

        Product("WebStorm", 49.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 }))

(6)fill()将集合中所有元素更新为指定值

val numbers = mutableListOf(1, 2, 3, 4)

numbers.fill(3)

println(numbers)

//[3, 3, 3, 3]

17、set操作

(1)union()获取并集。对于有序集合,操作数顺序决定元素顺序。a union b

(2)intersect()获取交集。a intersect b

(3)subtract()获取差集。a subtract b 

18、map操作

filter()、filterKeys()、filterValues()

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)

println(numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10 })

//{key11=11}

println(numbersMap.filterKeys { it.endsWith("1") })

//{key1=1, key11=11}

println(numbersMap.filterValues { it < 10 })

//{key1=1, key2=2, key3=3}

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