Kotlin中的集合框架

博客地址:sguotao.top/Kotlin-2018…

欲善其事,必利其器,在Java中集合框架占有很重要的地位,在Kotlin中也同样,想要能够在使用这些集合的时候,能够根据现实中的业务场景,信手拈来,就需要对这些集合有比较全面的了解。本篇将对比Java中的集和框架,对Kotlin中的集合框架进行梳理,首先简单回顾一下Java中的集合框架,接着重点介绍Kotlin中的集合框架,最后介绍Kotlin提供的一些关于集合框架的高阶函数。

Java中的集合框架

集合框架的用途是提供一个容器,用来存储对象,具体使用哪个容器,需要根据业务场景的需求,选择合适的容器。如果从容器的用途这个角度,Java提供了两种容器,Collection和Map,Collection是用来存储单个元素形式对象的集合,Map是用来存储键/值映射这样成对元素的集合。了解了这个后,再来看一下Java集合框架的全家福。

从图中可以看到我们常用的集合如LinkedLlist、ArrayList、HashSet、HashMap等清晰的继承关系,Java将一些对集合常用的方法封装在Collections和Arrays两个类中。集合都可以产生一个迭代器,List还能产生一个ListIterator的迭代器。最后简单对Java的集合框架总结一下:

  1. Java提供了两种类型的容器,Collection和Map;
  2. 常用的集合List和Set都是Collection接口的实现类,List存储的对象之间有指定的顺序,存储的对象可以重复,Set存储的对象之间没有指定的顺序,存储的对象不可以重复。

Kotlin中的集合框架

Kotlin中的集合框架,去掉了Java中历史遗留的一些结构,同时集合类型在Kotlin中可以是只读的,也可以是可变的,于是Kotlin中的集合框架就与Java中集合框架有如下的映射关系:

Java中的类型Kotlin中的只读类型Kotlin中的可变类型
Iterator<T>Iterator<T>MutableIterator<T>
Iterable<T>Iterable<T>MutableIterable<T>
Collection<T>Collection<T>MutableCollection<T>
Set<T>Set<T>MutableSet<T>
List<T>List<T>MutableList<T>
ListIterator<T>ListIterator<T>MutableListIterator<T>
Map<K, V>Map<K, V>MutableMap<K, V>
Map.Entry<K, V>Map.Entry<K, V>MutableMap.MutableEntry<K,V>

相应的给出Kotlin的集合框架图,从图中也可以看出,Kotlin集合中的可变类型都实现了只读类型,同时将一些对集合操作的方法,封装在了_Collections和_Arrays等文件中。由于Kotlin中存在扩展函数,因此在使用这些方法时,不是直接通过文件名+点的方式进行调用,而是就像集合自身的方法一样进行调用。从Java的角度看,就像这些方法是这些集合的成员函数。

了解了Kotlin的集合框架,那么实际用到的集合有哪些呢?在Kotlin collections包中可以找到这样一个文件TypeAliasesKt.class文件。

@file:kotlin.jvm.JvmVersion
package kotlin.collections

@SinceKotlin("1.1") public typealias RandomAccess = java.util.RandomAccess

@SinceKotlin("1.1") public typealias ArrayList<E> = java.util.ArrayList<E>
@SinceKotlin("1.1") public typealias LinkedHashMap<K, V> = java.util.LinkedHashMap<K, V>
@SinceKotlin("1.1") public typealias HashMap<K, V> = java.util.HashMap<K, V>
@SinceKotlin("1.1") public typealias LinkedHashSet<E> = java.util.LinkedHashSet<E>
@SinceKotlin("1.1") public typealias HashSet<E> = java.util.HashSet<E>

// also @SinceKotlin("1.1")
internal typealias SortedSet<E> = java.util.SortedSet<E>
internal typealias TreeSet<E> = java.util.TreeSet<E>
复制代码

可以看到,我们常用的一些集合如ArrayList、LinkedHashMap、HashMap、LinkedHashSet、HashSet等,在Kotlin中实际上对应的就是Java中的这些集合,Kotlin只是换了个别名而已,这些集合的存储结构与Java中是一样的,所以可以如同在Java中一样的方式使用这些集合。

集合中的高阶函数

前面说到Kotlin将一些对集合的扩展函数都封装在了_Collections、_Arrays这样的文件中,那么究竟有哪些扩展函数呢?了解一下,可以省去写很多工具方法的时间,而且稳定性可能会优于我们自己的工具方法。由于扩展函数数量比较多,这里将按照函数实现的功能,将这些函数分成下面几类。

一 总数函数

1.any 如果有一个元素符合给出的判断条件,返回true*

val list = listOf(1, 2, 3, 4, 5, 6)
val listwithNull = listOf(1, 2, 3, 4, null, 5, null, 6, null)
assertTrue(list.any { it % 2 == 0 })
复制代码

2.all 如果全部的元素符合给出的判断条件,返回true

assertTrue { list.all { it > 0 } }
复制代码

3.count 返回符合给出判断条件的元素的个数

assertEquals(3, list.count { it % 2 == 0 })
复制代码

4.fold 在一个初始值的基础上从第一项到最后一项进行累加

assertEquals(220, list.fold(10) { total, next -> total + next * 10 })
复制代码

5.foldRight 与fold类似,但顺序是从最后一项到第一项

assertEquals(31, list.foldRight(10) { total, next -> total + next })
复制代码

6.forEach 遍历所有元素并执行给定操作

list.forEach() { print(it) }
复制代码

7.forEachIndexed 与forEach类似,同时可以获取元素的index

list.forEachIndexed() { index, value -> println("position:$index,value:$value") }
复制代码

8.max 返回最大一项,如果没有返回null

assertEquals(6, list.max())
复制代码

9.maxBy 根据给定的函数,返回最大一项,如果没有返回null

assertEquals(1, list.maxBy { -it })
复制代码

10.min 返回最小一项,如果没有返回null

assertEquals(1, list.min())
复制代码

11.minBy 根据给定的函数,返回最小的一项,如果没有返回null

assertEquals(6, list.minBy { -it })
复制代码

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

assertTrue { list.none() { it >= 7 } }
复制代码

13.reduce 与fold类似,但没有初始值

assertEquals(21, list.reduce() { total, next -> total + next })
复制代码

14.reduceRight 与reduce类似,但顺序是从最后一项到第一项

assertEquals(21, list.reduceRight() { total, next -> total + next })
复制代码

15.sumBy 返回每一项通过函数转换后的数据总和

assertEquals(-21, list.sumBy { -it })
复制代码

二 过滤函数

16.drop 返回包含去掉前n个元素的所有元素的列表

assertEquals(listOf(5, 6), list.drop(4))
复制代码

17.dropWhile 返回去掉满足指定函数要求的,从第一个元素开始的所有元素的列表

assertEquals(listOf(4, 5, 6), list.dropWhile { it < 4 })
复制代码

18.dropLastWhile 返回去掉指定函数要求的,从最后一个元素开始的所有元素的列表

assertEquals(listOf(1, 2, 3, 4), list.dropLastWhile { it > 4 })
复制代码

19.filter 保留所有满足指定函数要求的元素

assertEquals(listOf(2, 4, 6), list.filter { it % 2 == 0 })
复制代码

20.filterNot 过滤掉所有满足指定函数要求的元素

assertEquals(listOf(1, 3, 5), list.filterNot { it % 2 == 0 })
复制代码

21.filterNotNull 保留所有不为null的元素

assertEquals(listOf(1, 2, 3, 4, 5, 6), listwithNull.filterNotNull())
复制代码

22.slice 保留list中指定index的元素

assertEquals(listOf(2, 4, 5), list.slice(listOf(1, 3, 4)))
复制代码

23.take 保留从第一个元素开始的n个元素

assertEquals(listOf(1, 2, 3), list.take(3))
复制代码

24.takeLast 保留从最后一个元素开始的n个元素

assertEquals(listOf(4, 5, 6), list.takeLast(3))
复制代码

25.takeWhile 保留从第一个元素开始,满足指定函数的元素

assertEquals(listOf(1, 2), list.takeWhile { it < 3 })
复制代码

三 映射函数

26.flatMap 遍历每一个元素,为每一个元素创建一个集合,最后把所有集合合并为一个集合

print(list)//list:[1,2,3,4,5,6]
//[1,2],[2,3],[3,4],[4,5],[5,6],[6,7] => [1,2,2,3,3,4,4,5,5,6,6,7]
println(list.flatMap { listOf(it, it + 1) })
复制代码

27.groupBy 返回一个根据指定函数分组的map

println(mapOf("odd" to listOf(1, 3, 5)))
println(mapOf("even" to listOf(2, 4, 6)))
println(list.groupBy { if (it % 2 == 0) "even" else "odd" })
复制代码

28.map 返回一个,每个元素都按照指定函数进行转换后的集合

assertEquals(listOf(2, 4, 6, 8, 10, 12), list.map { it -> it * 2 })
复制代码

29.mapIndexed 返回一个,每个元素按照包含元素index的指定函数转换后的集合

assertEquals(listOf(0, 2, 6, 12, 20, 30), list.mapIndexed { it, index -> index * it })
复制代码

30.mapNotNull 返回一个过滤掉null元素,并且非null元素按照指定函数进行转换后的集合

println(listwithNull)
println(listwithNull.mapNotNull { it })
复制代码

四 元素操作函数

31.contains 如果指定元素在集合中,返回true

assertTrue(list.contains(1))
复制代码

32.elementAt 返回指定index对应的元素,如果index越界,抛IndexOutOfBoundsException

assertEquals(1, list.elementAt(0))
复制代码

33.elementAtOrElse 返回指定index对应的元素,如果index越界,返回指定函数中设置的默认值

assertEquals(20, list.elementAtOrElse(10, { 2 * it }))
复制代码

34.elementAtOrNull 返回指定index对应的元素,如果index越界,返回null

assertNull(list.elementAtOrNull(10))
复制代码

35.first 返回第一个满足指定函数的元素,如果没有,抛出NoSuchElementException

assertEquals(2, list.first() { it % 2 == 0 })
复制代码

36.firstOrNull 返回第一个满足指定函数的元素,如果没有返回null

assertNull(list.firstOrNull() { it < 0 })
复制代码

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

assertEquals(-1, list.indexOf(7))
复制代码

38.indexOfFirst 返回第一个满足指定函数的元素的index,如果不存在返回-1

assertEquals(1, list.indexOfFirst { it % 2 == 0 })
复制代码

39.indexOfLast 返回最后一个满足指定函数的元素的index,如果不存在返回-1

assertEquals(5, list.indexOfLast { it % 2 == 0 })
复制代码

40.last 返回最后一个满足指定函数的元素,如果没有,抛出NoSuchElementException

println(list.last() { it % 2 == 0 })
复制代码

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

println(listwithNull.lastIndexOf(null))
复制代码

42.lastOrNull 返回最后一个满足指定函数的元素,如果没有返回null

assertNull(list.lastOrNull() { it < 0 })
复制代码

43.single 返回满足指定函数的单个元素,如果没有,或者满足条件的元素个数超过一个,抛出异常

assertEquals(1, list.single() { it < 2 })
复制代码

44.singleOrNull 返回满足指定函数的单个元素,如果没有,或者满足条件的元素个数超过一个,返回null

println(list.singleOrNull() { it % 2 == 0 })
复制代码

五 生产函数

45.partition 将一个给定的集合分割成两个集合,第一个集合是由匹配指定函数,返回true的元素组成。第二个集合是由匹配指定函数,返回false的元素组成。

assertEquals(Pair(listOf(1, 3, 5), listOf(2, 4, 6)), list.partition { it % 2 != 0 })
复制代码

46.plus 返回一个包含原集合和给定集合中所有元素的集合,可以使用“+”操作符

assertEquals(listOf(1, 2, 3, 4, 5, 6, 6, 7, 8), list + listOf(6, 7, 8))
复制代码

47.plusElement 在集合中添加元素

println(list.plusElement(7))
复制代码

48.zip 将两个集合按照下标进行配对,组成的Pair是由两个集合中相同index的元素组成,如果两个集合长度不一致,取短的集合的长度。

assertEquals(listOf(Pair(1, 'x'), Pair(2, 'y')), list.zip(listOf('x', 'y')))
复制代码

49.unzip 作用在包含Pair的集合上,依次取各个Pair的first和second值,放入List和List中,然后返回包含List和List的Pair

val listPair = listOf(Pair(1, 2), Pair('a', 'b'), Pair(3, 4), Pair('c', 'd'))
println(listPair)
println(listPair.unzip())
复制代码

六 顺序函数

50.reversed 返回一个与指定list顺序相反的list

println(list)
println(list.reversed())
复制代码

51.sorted 升序排序

println(list.sorted())
复制代码

52.sortBy 返回一个按照指定函数变换后的升序排序

println(list.sortedBy { it -> it % 3 })
复制代码

53.sortDescending 降序排序

println(list.sortedDescending())
复制代码

54.sortDescendingBy 返回一个按照指定函数变换后的降序排序

println(list.sortedByDescending { it -> it % 3 })
复制代码

学习资料

  1. Kotlin Bootcamp for Programmers
  2. Kotlin Koans

转载于:https://juejin.im/post/5bd97fce6fb9a022523c4a83

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值