Kotlin 学习笔记(十二)kotlin中 集合序列使用、操作符汇总、list和sequence比较

MilkyWayLadakh_ZH-CN7734727282_1920x1080.jpg

前言
本篇博客为本人学习Kotlin 中所遇到的问题,如果哪里写的不对,希望欧大佬帮忙指出,多谢。

1. 集合的基础使用

kotlin 中的集合主要为:Array、List、Set、Map , Sequence

1.1 数组

val arr = arrayOf("1",2,3,4)

1.2 List

不可变集合 ( listOf() )

val arr = arrayOf("1","2",3,4,5)   
val list1 = listOf(1,2,"3",4,"5")                // 随意创建         
val list2 = listOf<String>("1","2","3","4","5")  // 确定元素的值类型
val list3 = listOf(arr)                          // 可传入一个数组

以下代码是错误的。因为List<E>只能是不可变集合。而add、remove、clear等函数时MutableList中的函数
list1.add() 
list1.remove

可变集合 ( mutableListOf )

val arr = arrayOf("1","2",3,4)
val mutableList1 = mutableListOf(1,2,3,4,"5")                // 随意创建         
val mutableList2 = mutableListOf<String>("1","2","3","4","5")  // 确定元素的值类型
val mutableList3 = mutableListOf(arr)                          // 可传入一个数组
val mutableList : ArrayList<String>  // 这里的ArrayList<>和Java里面的ArrayList一致

mutableList1.add("6")  // 添加元素
mutableList1.add("7")
mutableList1.remove(1)   // 删除某一元素

1.3 Set

val set1 = setOf(1,2,"3","4","2",1,2,3,4,5)
val mutableSet1 = mutableSetOf(1,2,"3","4","2",1,2,3,4,5)

// 这里的HashSet<>和Java里面的HashSet<>一致
val mutableSet2 : HashSet<String>  

// 输出结果 : 1 2 3 4 2 3 4 5 

  当我们看到输出结果的时候 发现所有的重复 数据都没有了,这里的特点也是kotlin和java 保持了一致。

1.4 Map

// 以键值对的形式出现,键与值之间使用to

val map1 = mapOf("key1" to 2 , "key2" to 3)
val map2 = mapOf<Int,String>(1 to "value1" , 2 to "value2")
val mutableMap = mutableMapOf("key1" to 2 , "key1" to 3)

// 同Java中的HashMap
val hashMap = hashMapOf("key1" to 2 , "key1" to 3)   

val map = val map1 = mapOf("key1" to 2 , "key1" to 3 ,
                             "key1" to "value1" , "key2" to "value2")

//输出结果 key1      value1   , key2     value2

当我们的键存在重复时,集合会过滤掉之前重复的元素。value 只保留了最后一个元素。而过滤掉了之前key值相同的所有元素。

2 List 和 Sequence 选择使用

  相信大多Android 开发者都理解集合和序列的区别,那么我们应该如何更好的使用这两个?

总结List的使用场景:

  1. 量级比较小的集合元素(当数量比较少的时候 List 和 Sequence 的循环耗时相差无几)
  2. 访问索引元素 (Lists(集合) 是有索引的,Sequences(序列) 则必须逐项进行.其实和 java 中的 ArrayList 和 LinkedList 知识点差不多)
  3. 返回/传递给其他的函数 (每次迭代Sequences(序列) 时,都会计算元素。Lists(集合) 中的元素只计算一次,然后存储在内存中。)

我们这里之举一个例子通过耗时的循环来看下两者区别

Kotlin

list.map { it *3 }
  .filter { it % 2 == 0 }
  .count { it < 10 }

Kotlin code

      Object element$iv$iv;
      int it;
      while(var5.hasNext()) {
         element$iv$iv = var5.next();
         it = ((Number)element$iv$iv).intValue();
         Integer var12 = it * 3;
         destination$iv$iv.add(var12);
      }

      $receiver$iv = (Iterable)((List)destination$iv$iv);
      destination$iv$iv = (Collection)(new ArrayList());
      var5 = $receiver$iv.iterator();

      while(var5.hasNext()) {
         element$iv$iv = var5.next();
         it = ((Number)element$iv$iv).intValue();
         if (it % 2 == 0) {
            destination$iv$iv.add(element$iv$iv);
         }
      }

      $receiver$iv = (Iterable)((List)destination$iv$iv);
      if (!($receiver$iv instanceof Collection) || !((Collection)$receiver$iv).isEmpty()) {
         int count$iv = 0;
         Iterator var13 = $receiver$iv.iterator();

         while(var13.hasNext()) {
            Object element$iv = var13.next();
            int it = ((Number)element$iv).intValue();
            if (it < 10) {
               ++count$iv;
            }
         }
      }

  你会发现Kotlin编译器会创建三个while循环.而Sequences则只会存在一个循环,所以在循环多的情况下 还是Sequences 比较快一点。
kotlin

    val result = list.asSequence()
            .map{ println("In Map"); it * 2 }
            .filter { println("In Filter");it % 3  == 0 }
    println("Before Average")
    println(result.average())

Kotlin code

      List list = CollectionsKt.listOf(new Integer[]{1, 2, 3, 4, 5, 6});
      Sequence result = SequencesKt.filter(SequencesKt.map(CollectionsKt.asSequence((Iterable)list), (Function1)null.INSTANCE), (Function1)null.INSTANCE);
      String var3 = "Before Average";
      System.out.println(var3);
      double var5 = SequencesKt.averageOfInt(result);
      System.out.println(var5);

  序列(Sequences) 的秘诀在于它们是共享同一个迭代器(iterator) ---序列允许 map操作 转换一个元素后,然后立马可以将这个元素传递给 filter操作 ,而不是像集合(lists) 一样等待所有的元素都循环完成了map操作后,用一个新的集合存储起来,然后又遍历循环从新的集合取出元素完成filter操作。

3. 操作符汇总

  下面对这6类操作符进行一一的讲解,不过这里就不对他们的源码进行分析。大多都存在于_Collections.kt这个文件中。下边的测试代码和运行结果 我都 将结果和 方法放在一起了 好对比

3.1 元素操作符

  • contains(元素) : 检查集合中是否包含指定的元素,若存在则返回true,反之返回false
  • elementAt(index) : 获取对应下标的元素。若下标越界,会抛出IndexOutOfBoundsException(下标越界)异常,同get(index)一样
  • elementAtOrElse(index,{...}) : 获取对应下标的元素。若下标越界,返回默认值,此默认值就是你传入的下标的运算值
  • elementAtOrNull(index) : 获取对应下标的元素。若下标越界,返回null
  • first() : 获取第一个元素,若集合为空集合,这会抛出NoSuchElementException异常
  • first{} : 获取指定元素的第一个元素。若不满足条件,则抛出NoSuchElementException异常
  • firstOrNull() : 获取第一个元素,若集合为空集合,返回null
  • firstOrNull{} : 获取指定元素的第一个元素。若不满足条件,返回null
  • getOrElse(index,{...}) : 同elementAtOrElse一样
  • getOrNull(index) : 同elementAtOrNull一样
  • last () : 同first()相反
  • last {} : 同first{}相反
  • lastOrNull{} : 同firstOrNull()相反
  • lastOrNull() : 同firstOrNull{}相反
  • indexOf(元素) : 返回指定元素的下标,若不存在,则返回-1
  • indexOfFirst{...} : 返回第一个满足条件元素的下标,若不存在,则返回-1
  • indexOfLast{...} : 返回最后一个满足条件元素的下标,若不存在,则返回-1
  • single() : 若集合的长度等于0,则抛出NoSuchElementException异常,若等于1,则返回第一个元素。反之,则抛出IllegalArgumentException异常
  • single{} : 找到集合中满足条件的元素,若元素满足条件,则返回该元素。否则会根据不同的条件,抛出异常。这个方法慎用
  • singleOrNull() : 若集合的长度等于1,则返回第一个元素。否则,返回null
  • singleOrNull{} : 找到集合中满足条件的元素,若元素满足条件,则返回该元素。否则返回null
  • forEach{...} : 遍历元素。一般用作元素的打印
  • forEachIndexed{index,value} : 遍历元素,可获得集合中元素的下标。一般用作元素以及下标的打印
  • componentX() : 这个函数在前面的章节中提过多次了。用于获取元素。其中的X只能代表1..5。详情可看下面的例子

eg:

val list = listOf("kotlin","Android","Java","PHP","Python","IOS")

println(list.contains("JS"))   // false

println(list.elementAt(2))  // Java
println(list.elementAtOrElse(10,{it}))   // 10 
println(list.elementAtOrNull(10))   // null

println(list.get(2))  //  Java
println(list.getOrElse(10,{it}))  // 10
println(list.getOrNull(10))  // null

println(list.first())   //  kotlin
println(list.first{ it == "Android" })  // Android
println(list.firstOrNull())   // kotlin
println(list.firstOrNull { it == "Android" })   // Android

println(list.last())   // IOS
println(list.last{ it == "Android" })   // Android
println(list.lastOrNull())  // IOS
println(list.lastOrNull { it == "Android" })  // Android

println(list.indexOf("Android"))  // 1
println(list.indexOfFirst { it == "Android" })  //  1
println(list.indexOfLast { it == "Android" })   //  1

val list2 = listOf("list")
// 只有当集合只有一个元素时,才去用这个函数,不然都会抛出异常。
println(list2.single())      // list
 //当集合中的元素满足条件时,才去用这个函数,不然都会抛出异常。若满足条件返回该元素
println(list2.single { it == "list" })   // list
// 只有当集合只有一个元素时,才去用这个函数,不然都会返回null。
println(list2.singleOrNull())    // list
//当集合中的元素满足条件时,才去用这个函数,不然返回null。若满足条件返回该元素
println(list2.singleOrNull { it == "list" })   // list 

list.forEach { println(it) } 
// kotlin
// Android
// Java
// PHP
// Python
// IOS

list.forEachIndexed { index, it -> println("index : $index \t value = $it") }
/**
index : 0    value = kotlin
index : 1    value = Android
index : 2    value = Java
index : 3    value = PHP
index : 4    value = Python
index : 5    value = IOS
**/

  // 等价于`list[0]  <=> list.get(0)`
println(list.component1())    //  kotlin
....
 // 等价于`list[4]  <=> list.get(4)`
println(list.component5())   // Python

3.2 顺序操作符

  • reversed() : 反序。
  • sorted() : 升序。
  • sortedBy{} : 根据条件升序。把不满足条件的放在前面,满足条件的放在后面
  • sortedDescending() : 降序。
  • sortedByDescending{} : 根据条件降序。

eg:

    val list1 = listOf(-1,-2,1,3,5,6,7,2,4)
    // 反序
    println(list1.reversed())    // [4, 2, 7, 6, 5, 3, 1, -2, -1]
    // 升序
    println(list1.sorted())   // [-2, -1, 1, 2, 3, 4, 5, 6, 7]
    // 根据条件升序,即把不满足条件的放在前面,满足条件的放在后面
    println(list1.sortedBy { it % 2 == 0})  // [-1, 1, 3, 5, 7, -2, 6, 2, 4]
    // 降序
    println(list1.sortedDescending())   // [7, 6, 5, 4, 3, 2, 1, -1, -2]
    // 根据条件降序,和`sortedBy{}`相反
    println(list1.sortedByDescending { it % 2 == 0 })   // [-2, 6, 2, 4, -1, 1, 3, 5, 7]

3.3 映射操作符

  • map{...} : 把每个元素按照特定的方法进行转换,组成新的集合。
  • mapNotNull{...} : 同map{}函数的作用相同,过滤掉转换之后为null的元素
  • mapIndexed{index,result} : 把每个元素按照特定的方法进行转换,只是其可以操作元素的下标(index),组成新的集合。
  • mapIndexedNotNull{index,result} : 同mapIndexed{}函数的作用相同,只是过滤掉转换之后为null的元素
  • flatMap{...} : 根据条件合并两个集合,组成新的集合。
  • groupBy{...} : 分组。即根据条件把集合拆分为为一个Map<K,List<T>>类型的集合。

eg:

    val list1 = listOf("kotlin","Android","Java","PHP","JavaScript")

    println(list1.map { "str-".plus(it) })
    //[str-kotlin, str-Android, str-Java, str-PHP, str-JavaScript]

    println(list1.mapNotNull { "str-".plus(it) })
    // [str-kotlin, str-Android, str-Java, str-PHP, str-JavaScript]
    
    println(list1.mapIndexed { index, str ->
        index.toString().plus("-").plus(str)
    })
    //[0-kotlin, 1-Android, 2-Java, 3-PHP, 4-JavaScript]
    
    println(list1.mapIndexedNotNull { index, str ->
        index.toString().plus("-").plus(str)
    })
    // [0-kotlin, 1-Android, 2-Java, 3-PHP, 4-JavaScript]
    
    println( list1.flatMap { listOf(it,"new-".plus(it)) })
    //[kotlin, new-kotlin, Android, new-Android, Java, new-Java, PHP, new-PHP, JavaScript, new-JavaScript]
    
    println(list1.groupBy { if (it.startsWith("Java")) "big" else "latter" })
    // {latter=[kotlin, Android, PHP], big=[Java, JavaScript]}

3.4 过滤操作符

  • filter{...} : 把不满足条件的元素过滤掉
  • filterIndexed{...} : 和filter{}函数作用类似,可以操作集合中元素的下标
  • filterNot{...} : 和filter{}函数的作用相反
  • filterNotNull() : 过滤掉集合中为null的元素。
  • take(num) : 返回集合中前num个元素组成的集合
  • takeWhile{...} : 循环遍历集合,从第一个元素开始遍历集合,当第一个出现不满足条件元素的时候,退出遍历。然后把满足条件所有元素组成的集合返回。
  • takeLast(num) : 返回集合中后num个元素组成的集合
  • takeLastWhile{...} : 循环遍历集合,从最后一个元素开始遍历集合,当第一个出现不满足条件元素的时候,退出遍历。然后把满足条件所有元素组成的集合返回。
  • drop(num) : 过滤集合中前num个元素
  • dropWhile{...} : 相同条件下,和执行takeWhile{...}函数后得到的结果相反
  • dropLast(num) : 过滤集合中后num个元素
  • dropLastWhile{...} : 相同条件下,和执行takeLastWhile{...}函数后得到的结果相反
  • distinct() : 去除重复元素
  • distinctBy{...} : 根据操作元素后的结果去除重复元素
  • slice : 过滤掉所有不满足执行下标的元素。

eg:

    val list1 = listOf(-1,-3,1,3,5,6,7,2,4)
    val list2 = listOf(1,3,4,5,null,6,null,10)
    val list3 = listOf(1,1,5,2,2,6,3,3,7,4)

    println(list1.filter { it > 1  })   // [3, 5, 6, 7, 2, 4]
    println(list1.filterIndexed { index, result ->
        index < 5 && result > 3
    })
    //  [5] 

    println(list1.filterNot { it > 1 })   //  [-1, -3, 1]
    println(list2.filterNotNull())   //   [1, 3, 4, 5, 6, 10]

    println(list1.take(5))    //  [-1, -3, 1, 3, 5]
    println(list1.takeWhile { it < 5 })   //  [-1, -3, 1, 3]
    println(list1.takeLast(5))   //  [5, 6, 7, 2, 4]
    println(list1.takeLastWhile { it > 5 })   //  []

    println(list1.drop(5))   // [6, 7, 2, 4]
    println(list1.dropWhile { it < 5 })   //  [5, 6, 7, 2, 4]
    println(list1.dropLast(5))  // [-1, -3, 1, 3]
    println(list1.dropLastWhile { it > 5 })  // [-1, -3, 1, 3, 5, 6, 7, 2, 4]

    println(list3.distinct())  //  [1, 5, 2, 6, 3, 7, 4]
    println(list3.distinctBy { it + 2 })  //  [1, 5, 2, 6, 3, 7, 4]

    println(list1.slice(listOf(1,3,5,7)))  //  [-3, 3, 6, 2]
    println(list1.slice(IntRange(1,5)))  //   [-3, 1, 3, 5, 6]

3.5 生产操作符

  • plus() : 合并两个集合中的元素,组成一个新的集合。也可以使用符号+
  • zip : 由两个集合按照相同的下标组成一个新集合。该新集合的类型是:List<Pair>
  • unzip : 和zip的作用相反。把一个类型为List<Pair>的集合拆分为两个集合。看下面的例子
  • partition : 判断元素是否满足条件把集合拆分为有两个Pair组成的新集合

eg:

    val list1 = listOf(1,2)
    val list2 = listOf("kotlin","Android","Java")

    println(list1.plus(list2))  // [1, 2, kotlin, Android, Java]
    println(list1 + list2)   //  [1, 2, kotlin, Android, Java]
    // 组成的新集合由元素少的原集合决定
    println(list1.zip(list2))   //  [(1, kotlin), (2, Android)]
    // 组成的新集合由元素少的原集合决定
    println(list1.zip(list2){
        it1,it2-> it1.toString().plus("-").plus(it2)
    })  //  [1-kotlin, 2-Android]
    
    val newList = listOf(Pair(1,"Kotlin"),Pair(2,"Android"),Pair(3,"Java"))
    println(newList.unzip())   //  ([1, 2, 3,], [Kotlin, Android, Java])

    println(list2.partition { it.startsWith("Ja") })  //  ([Java], [kotlin, Android])

3.6 统计操作符

  • any() : 判断是不是一个集合,若是,则在判断集合是否为空,若为空则返回false,反之返回true,若不是集合,则返回hasNext
  • any{...} : 判断集合中是否存在满足条件的元素。若存在则返回true,反之返回false
  • all{...} : 判断集合中的所有元素是否都满足条件。若是则返回true,反之则返回false
  • none() : 和any()函数的作用相反
  • none{...} : 和all{...}函数的作用相反
  • max() : 获取集合中最大的元素,若为空元素集合,则返回null
  • maxBy{...} : 获取方法处理后返回结果最大值对应那个元素的初始值,如果没有则返回null
  • min() : 获取集合中最小的元素,若为空元素集合,则返回null
  • minBy{...} : 获取方法处理后返回结果最小值对应那个元素的初始值,如果没有则返回null
  • sum() : 计算出集合元素累加的结果。
  • sumBy{...} : 根据元素运算操作后的结果,然后根据这个结果计算出累加的值。
  • sumByDouble{...} : 和sumBy{}相似,不过sumBy{}是操作Int类型数据,而sumByDouble{}操作的是Double类型数据
  • average() : 获取平均数
  • reduce{...} : 从集合中的第一项到最后一项的累计操作。
  • reduceIndexed{...} : 和reduce{}作用相同,只是其可以操作元素的下标(index)
  • reduceRight{...} : 从集合中的最后一项到第一项的累计操作。
  • reduceRightIndexed{...} : 和reduceRight{}作用相同,只是其可以操作元素的下标(index)
  • fold{...} : 和reduce{}类似,但是fold{}有一个初始值
  • foldIndexed{...} : 和reduceIndexed{}类似,但是foldIndexed{}有一个初始值
  • foldRight{...} : 和reduceRight{}类似,但是foldRight{}有一个初始值
  • foldRightIndexed{...} : 和reduceRightIndexed{}类似,但是foldRightIndexed{}有一个初始值

eg:

    val list1 = listOf(1,2,3,4)
    println(list1.any())   // true
    println(list1.any{it > 10})   //  false
    println(list1.all { it > 2 })   //  false
    println(list1.none())   // false
    println(list1.none{ it > 2})    //  false
    println(list1.max())   //  4
    println(list1.maxBy { it + 2 })   // 4
    println(list1.min())    //  1
    println(list1.minBy { it + 2 })   //  1
    println(list1.sum())   //  10
    println(list1.sumBy { it + 2 })   // 18
    println(list1.sumByDouble { it.toDouble() })   //  10.0
    println(list1.average())    //  2.5
    println(list1.reduce { result, next -> result  + next})   //  10
    println(list1.reduceIndexed { index, result, next ->
        index + result + next
    })  //   16
    println(list1.reduceRight { result, next -> result  + next })   //   10
    println(list1.reduceRightIndexed {index, result, next ->
        index + result + next
    })  //  13
    println(list1.fold(3){result, next -> result  + next})  //  13
    println(list1.foldIndexed(3){index,result, next ->
        index + result  + next
    })  //  19
    println(list1.foldRight(3){result, next -> result  + next})   //  13
    println(list1.foldRightIndexed(3){index,result, next ->
        index + result  + next
    })  //  19
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258

推荐阅读更多精彩内容