• 【Scala】07 集合


    分三大类:

    序列 Seq

    集 Set

    映射 Map

    所有集合类型都扩展自Iterable特质(可迭代的)

    所有集合类型都提供【可变】和【不可变】的版本

    归纳在下面两个包中

    scala.collections.immutable 不可变的

    意思这个集合对象不可改变,每一次修改即返回新的对象,不对原始集合对象修改

    等同java.lang.String

    scala.collections.mutable 不可变的

    意思这个集合对象可改变,每一次修改即返回原始的对象,等同java.lang.StringBuilder

    固定数组Array的操作:

    package cn
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
        // 推倒类型变量, new 新创建 Array表示数组 [String]表示数组元素的类型 (10) 表示数组的长度
        val strings = new Array[String](10)
    
        // 数组的长度属性
        val len = strings.length
    
        // 对指定索引上的元素修改赋值,也可以用来读取
        strings(0) = "aaa"
    
        // 创建方式2
        val arr1 = Array.apply(10, 20, 30, 40)
        val arr2 = Array(10, 20, 30, 40) // 直接Array就是apply的缩写
    
        // 遍历
        // for(el <- 0 to arr1.length - 1)
        // for(el <- 0 until arr1.length)
        // for(el <- arr1.indices)
        // for(el <- arr1)
        for(el <- 0 until  arr1.length) println(el)
    
        // 迭代遍历
        val itr = arr2.iterator
        while (itr.hasNext) println(itr.next())
    
        // forEach方法
        arr1.foreach(el => {
          println(el)
        })
        arr2.foreach(println)
    
        // 添加元素
        val newArr1 = arr1.:+(123) // 不可变数组添加元素是一个新的数组 :+(element) 在末尾加
        val newArr2 = newArr1.+:(123) // +:(element) 在开头添加
    
        // 使用这种添加方式
        val newArr3 = newArr2 :+ 16 // 对象(参数)
        val newArr4 = 16 +: newArr2// (参数) 对象
    
        // 简洁明了的添加元素操作
        val newArr5 = 10 +: 12 +: 33 +: newArr4 :+ 2 :+ 11 :+ 5; //
      }
    }

     添加元素的方法:

    package cn
    
    import scala.collection.mutable.ArrayBuffer
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
    
        // 缓冲数组
        val value = new ArrayBuffer[Any]
    
        // 不要这样赋值 会索引越界, 因为value里面什么都没有,需要存在确定的元素才可以这样去访问
        value(0) = 100 // 访问元素和固定数组是一样的
    
        // 添加元素
        value += 10 // 使用的是直接加等于
        77 +=: value
        // value.append(100) append方法被移除了?
        value.prepend(12, 22, 33) // prepend方法标记为过时的
        value.insert(1, 0)
        value.insertAll(1, value)
        value.prependAll(value)
      }
    }

    固定List :

    package cn
    
    import scala.collection.mutable
    import scala.collection.mutable.ArrayBuffer
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
    
    
        // 创建固定List
        val list = List(false, 10, "string") // 能装填不同数据类型的元素
    
        println(list) // List(false, 10, string)
    
        println(list(1)) // 可以读取
        // list(1) = 10 // 但是无法写入
    
    
        // 遍历List的每一个元素
        list.foreach(println)
    
        // 添加元素 因为是固定的对象,所以添加元素就必须要返回新的对象
        val l2 = list.+:(25) // 从头部添加
        val l3 = list :+ 25 // 从尾部添加
    
        println(l2)
        println(l3)
    
        val l4 = l3.::(50) // 从头部添加
        println(l4)
    
        println(Nil) // Nil 是一个空List对象
        val l5 = 40 :: Nil // 参数写前面,对象调用写后面的语法
    
        // 所以就有像这种数组的声明方式
        val l6 = 100 :: 80 :: 60 :: 40 :: 20 :: Nil
        println(l6) // List(100, 80, 60, 40, 20)
    
        val l7 = l6 :: l6 // 该方法会把List对象做为元素也装进这个List对象中
        println(l7) // List(List(100, 80, 60, 40, 20), 100, 80, 60, 40, 20)
    
        // 如果需要装填的是里面得元素 则使用三冒号实现
        val l8 = l6 ::: l6
        println(l8)
    
        // 或者使用这个符号 ++ 作用和三冒号是一样的
        val l9 = l6 ++l8
      }
    }

    可变List:

    package cn
    
    import scala.collection.mutable
    import scala.collection.mutable.{ArrayBuffer, ListBuffer}
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
    
    
        // 可变list
    
    
        // 创建
        val lb1 : ListBuffer[Int] = new ListBuffer[Int]() // 方式1
        val lb2 = ListBuffer(12, 30, 50) // 方式2 (推荐这种伴生对象实现)
    
        // 添加元素
        lb1.append(112) // 后置追加
    
        lb2.prepend(122) // 前置追加
    
        lb1.insert(0, 123) // 指定索引位置追加 教程上可以追加多个,但是这个版本好像不支持了
    
        // +=: 表示前置追加, += 表示后置追加
        31 +=: 33 +=: lb1 += 12 += 35
    
        // 合并两个List并且返回一个新的List对象
        val lb3 = lb1 ++ lb2
    
        // 把lb2的元素合并到lb1中
        lb1 ++= lb2
    
        // 反过来lb1的元素合并到lb2中
        lb1 ++=: lb2
    
        // 和固定List不一样,ListBuffer是支持修改的
        lb1(1) = 100
      }
    }

    不可变Set & 可变Set

    package cn
    
    import scala.collection.mutable
    import scala.collection.mutable.{ArrayBuffer, ListBuffer}
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
    
    
        // Set会覆盖重复的元素 不可变类型
        val set = Set(12, 33, 44, 44)
    
        // 添加元素
        val set2 = set.+(11)
        val set3 = set2 + 22
    
        // 合并Set对象
        val set4 = set2 ++ set3
    
        // 删除元素
        val set5 = set4 - 100
    
    
        // 可变Set
        val mtbSet = mutable.Set(10, 10, 40)
    
        mtbSet + 33
    
        // 推荐直接调用方法
    
        mtbSet += 45
        mtbSet.add(45) // 返回添加结果
    
        mtbSet -= 45
        mtbSet.remove(45) // 返回添加结果
        
        // 合并Set
    
        // 合并两个Set返回到新Set对象中
        val mtbSet1 = mtbSet ++ mtbSet
    
        // 合并到 Set1对象数组
        mtbSet ++= mtbSet
        
      }
    }

    不可变Map

    package cn
    
    import scala.collection.mutable
    import scala.collection.mutable.{ArrayBuffer, ListBuffer}
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
    
        // 创建Map // 支持多个键值对创建
        val map : Map[String, Integer] = Map(
          "A" -> 0,
          "B" -> 12,
          "C" -> 33
        )
    
        println(map) // Map(A -> 0, B -> 12, C -> 33)
    
        println(map.getClass) // class scala.collection.immutable.Map$Map3
    
        // 遍历,元素是每一个键值对
        map.foreach(println)
    
        // 扩展
        map.foreach( (keyValue : (String, Integer)) => println(keyValue) )
    
        // 按Key遍历
        for(key <-  map.keys) {
          println(s"key : $key & value : ${map.get(key)}")
        }
    
        // 要直接获取Value -> map.get(Key).get
        for(key <-  map.keys) {
          println(s"key : $key & value : ${map.get(key).get}")
        }
    
        // 如果Value是空的,可能发生异常,采用安全的获取方法是 map.getOrElse(key, defaultValue) 设置缺省值
        for(key <-  map.keys) {
          println(s"key : $key & value : ${map.getOrElse(key, 0)}")
        }
    
        /**
         * key : A & value : Some(0)
         * key : B & value : Some(12)
         * key : C & value : Some(33)
         *
         * Value可能是一个NULL值,所以使用Option封装了一层 Some是一个Option子类
         */
    
        // Map 也支持像数组或者List那种方式访问值
        println(map("A"))
      }
    }

    可变Map和不可变Map调用的操作方法一样

    多了可操作的方法

    package cn
    
    import scala.collection.mutable
    import scala.collection.mutable.{ArrayBuffer, ListBuffer}
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
    
        // 创建可变Map // 支持多个键值对创建
        val map : mutable.Map[String, Integer] = mutable.Map(
          "A" -> 0,
          "B" -> 12,
          "C" -> 33
        )
        println(map) // Map(A -> 0, B -> 12, C -> 33)
        println(map.getClass) // class scala.collection.mutable.HashMap
    
        // 可变Map就支持元素的添加和移除
        map.put("D", 22) // 添加元素1
        map += ("E", 33) // 添加元素2
    
        map.remove("D") // 移除元素1
        map -= "E" // 移除元素2
        map -= ("E", 33) // 移除元素3
    
        // 遍历,元素是每一个键值对
        map.foreach(println)
    
    
        val map2 : mutable.Map[String, Integer] = mutable.Map(
          "A" -> 0,
          "B" -> 12,
          "C" -> 33
        )
    
        map ++= map2 // 合并Map2的元素给Map(覆盖已存在的Key&Value)
    
        // 或者合并返回新的map对象
        val map3 = map ++ map2
        // 扩展
        map.foreach( (keyValue : (String, Integer)) => println(keyValue) )
    
        // 按Key遍历
        for(key <-  map.keys) {
          println(s"key : $key & value : ${map.get(key)}")
        }
    
        // 要直接获取Value -> map.get(Key).get
        for(key <-  map.keys) {
          println(s"key : $key & value : ${map.get(key).get}")
        }
    
        // 如果Value是空的,可能发生异常,采用安全的获取方法是 map.getOrElse(key, defaultValue) 设置缺省值
        for(key <-  map.keys) {
          println(s"key : $key & value : ${map.getOrElse(key, 0)}")
        }
    
        /**
         * key : A & value : Some(0)
         * key : B & value : Some(12)
         * key : C & value : Some(33)
         *
         * Value可能是一个NULL值,所以使用Option封装了一层 Some是一个Option子类
         */
    
        // Map 也支持像数组或者List那种方式访问值
        println(map("A"))
      }
    }

    元组操作:

    package cn
    
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
        // 元组 通用数据类型容器,没有数据类型限制,但是最多存放22个元素?
        val tuple = ("String", 100, false, 3.14, "C")
    
        // 显式要求数据类型
        val tuple2 : (String, Int, Boolean, Double, Char) = ("String", 100, false, 3.14, 'C')
    
        // Map的键值对就是元组,只是个数固定是2 一个Key 一个Value
    
    
        // 访问元组的元素可以直接调用 tuple._index
        println(tuple._2) // 这种方式第一个是 _1 从1开始
        println(tuple2.productElement(0)) // 调用productElement(index) 是从0开始
    
        // 使用迭代器遍历访问
        for (elem <- tuple.productIterator) println(elem)
    
        // 元组支持嵌套元组,元组本身也算一种类型
        val tuple3 = (1, true, tuple, tuple2)
    
        for (elem <- tuple3.productIterator) println(elem)
        
        // 同样的操作可以连续调用
        println(tuple3._3._2)
      }
    }

    通用集合操作:

    package cn
    
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
    
        // 集合类型通用操作
        val list = List(1, 2, 3, 4, 5)
        println(list.length) // 获取长度
    
        val set = Set(1, 2, 3, 4, 5)
        println(set.size) // set不是长度属性,获取的是Size大小
    
        // 数组或者List可以直接遍历拿到元素
        for(el <- list) println(el)
    
        // set没有长度一说,需要通过迭代器执行
        for(el <- set.iterator) println(el)
    
        // 使用mkString转换为字符串
        println(list.mkString(","))
    
        // 判断是否包含某元素
        println(set.contains(23))
      }
    }

    衍生集合操作

    package cn.dzz
    
    object Main {
    
      def main(args: Array[String]): Unit = {
    
        // 衍生集合操作
        val list1 = List(1, 3, 5, 7, 8, 10, 113)
        val list2 = List(2, 4, 5, 7, 9, 10, 11)
    
        // 获取集合的头
        println(list1.head)
    
        // 获取集合的尾部 (不是头就是尾?) 意思是返回除了头部 返回后面所有的元素(新的List对象)
        println(list1.tail)
    
        // 获取集合的最后一个元素
        println(list1.last)
    
        // 获取集合除最后一个元素的所有元素
        println(list1.init)
    
        // 反转
        println(list1.reverse)
    
        // 获取指定位置长度的元素1
        println(list1.take(3)) // 获取前面3个元素
    
        // 获取指定位置长度的元素2
        println(list1.takeRight(3)) // 从右边开始获取3个元素
    
        // 移除前后的元素
        println(list1.drop(3)) // 从左边移除3个元素
        println(list1.dropRight(3)) // 从右边移除三个元素
    
        // 并集  A集合和B集合相同的元素原封不动  Set类会做去重处理
        val unionList = list1.union(list2)
        val unionList2 = list1 ::: list2
    
        // 交集 取出AB集合共同的部分
        val intersectList = list1.intersect(list2)
    
        // 差集 取出AB集合所独有的部分
        val diffList = list1.diff(list2) // 属于List1,但是不属于List2的元素
    
        // 拉链 ? 将两个集合合并成一个二元组集合
        println(list1.zip(list2))
    
        // 滑窗 固定筛选长度,可以偏移量的获取集合中的元素
        println(list1.sliding(3)) // 返回的是一个Iterator 默认步长是1,可调用重载  println(list1.sliding(3), 3)这样
    
        // 获取滑窗筛选的元素
        for (el <- list1.sliding(3)) println(el)
      }
    
    }

    集合计数方法:

    简单的聚合计算和排序处理:

    package cn.dzz
    
    object Main {
    
      def main(args: Array[String]): Unit = {
        // 集合的聚合处理
        val list = List(2, 42, 1213, 33, 44)
        
        // 求和
        println(list.sum)
    
        // 最大值
        println(list.max)
        
        val list2 = List(("A", 2), ("B", 42), ("C", 1213), ("D", 33), ("E", 44))
        // 如果是复杂类型的元素。 可以重写maxBy方法来执行排序
        list2.maxBy( (tuple :(String, Int)) => tuple._2) // 按照元组的第二元素类型获取最大值(作为排序的标准)
        list2.maxBy(_._2) // 可以缩写成这样
    
        // 乘积
        println(list.product)
    
        // 最小值
        println(list.min)
    
        // 排序
        println(list.sorted) // 升序排序
        println(list.sorted.reverse) // 降序排序
    
        // 复杂类型按指定元素类型排序
        println(list2.sortBy(_._2))
    
        println(list2.sortBy(_._2).reverse)
    
        // 指定排序方式
        println(list.sortWith(_ > _))
    
        // 复杂类型的话
        /**
         *     list2.sortWith( (a : (String, Int), b : (String, Int)) => {
         *       a._2 > b._2
         *     })
         */
        println(list2.sortWith(_._2 > _._2))
        // 其实像这种排序和比较大小的,在JS里面就是存在的,包括Jquery,也不是什么新鲜的东西了,语法很类似,
        // 只是JS还是比较强调方法,不允许这种极致的缩写语法
      }
    
    }

    复杂函数处理:

    package cn
    
    import scala.collection.mutable
    
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
        val list = List(1, 2, 3, 4, 6, 10, 22)
    
        // - - - - - 过滤 - - - - -
        // 只获取偶数元素
        val evenList = list.filter(el => el % 2 == 0) // filter方法 自定义过滤的条件,函数结果必须是一个Boolean,符合条件的元素会被收集
        println(evenList)
        // 只获取奇数
        println(list.filter(_ % 2 == 1))
    
        // - - - - - 转换 toMap - - - - -
        // 将List的每个元素乘2处理
        println(list.map(el => el * 2))
    
        // - - - - - 扁平化 - - - - -
        val nestedList : List[List[Int]] = List(
          List(1, 2, 3, 4, 5, 10),
          List(1, 2, 3, 4, 5, 9),
        )
        // 把一个立体的数据类型合并成一个简单List对象
    
        // 常规处理
        val flatList = nestedList(0) ::: nestedList(1)
        println(flatList)
    
        // 直接调用已封装好的参数
        val flatList2 = nestedList.flatten
        println(flatList2)
    
        // - - - - -  扁平化和映射 - - - - -
        val strList = List(
          "username root",
          "password 123456",
          "host 127.0.0.1",
          "port 3308"
        )
        val splitList: List[Array[String]] = strList.map(str => str.split(" ")) // 分词
        println(splitList)
    
        val flattenList = splitList.flatten
        println(flattenList)
    
        // 换成flatMap直接处理完成
        val flatMapList = strList.flatMap(_.split(" "))
        println(flatMapList)
    
        // - - - - - 分组 GROUP BY - - - - -
    
        val list2 = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
    
        // 将List直接变成奇偶两组
        val groupMap = list2.groupBy(_ % 2)
        println(groupMap) // HashMap(0 -> List(2, 4, 6, 8), 1 -> List(1, 3, 5, 7, 9))   Map[Int, List[Int]]
    
        val groupMap2 = list2.groupBy(data => {
          if (data % 2 == 0) "偶" else "奇"
        })
        println(groupMap2) //  Map[String, List[Int]] HashMap(偶 -> List(2, 4, 6, 8), 奇 -> List(1, 3, 5, 7, 9))
    
        // 给定一组词,按首次母进行区分
        val countryList = List(
          "China",
          "America",
          "Canada",
          "Japan",
          "India",
          "Australia",
          "Russia",
        )
        println(countryList.groupBy(_.charAt(0)))
        // HashMap(J -> List(Japan), A -> List(America, Australia), I -> List(India), C -> List(China, Canada), R -> List(Russia))
    
        // - - - - - 简化,规约 reduce - - - - -
        val list4 = List(1, 2, 3, 4)
    
        println(list4.reduce(_ + _)) // 10
        println(list4.reduceRight(_ + _)) // 从右边开始执行
        println(list4.reduceLeft(_ + _)) // 从左边开始执行
    
        println(list4.reduce(_ - _)) // -8
        println(list4.reduceRight(_ - _)) // -2
        println(list4.reduceLeft(_ - _)) // 从左边开始执行 -8
    
    
        // - - - - - 折叠? fold Reduce扩展 - - - - -
        println(list4.fold(10)(_ + _)) // 10 + 1 + 2 + 3 + 4
        println(list4.foldLeft(10)(_ + _))
        println(list4.foldLeft(10)(_ - _))
        println(list4.foldRight(10)(_ - _)) // 1 - (2 - (3 - (4 - 10)))
    
        // - - - - - Map合并 - - - - -
        val map1 = Map(
          "A" -> 1,
          "B" -> 2,
          "C" -> 3,
        )
        val map2 = mutable.Map(
          "A" -> 4,
          "B" -> 5,
          "C" -> 6,
          "D" -> 9,
        )
        println(map1 ++ map2) // Map(A -> 4, B -> 5, C -> 6, D -> 9)
        // 要实现Value相加,而不是进行覆盖
    
        val map3 = map1.foldLeft(map2)( (mergedMap, mp) => {
            val key = mp._1
            val value = mp._2
            mergedMap(key) = mergedMap.getOrElse(key, 0) + value
            mergedMap
        })
      }
    }

    单词计数案例

    package cn
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
        
        // 单词计数 案例
        val stringList = List(
          "hello",
          "hello scala",
          "hello world",
          "hello spark",
          "hello flink",
        )
    
        // 对字符串进行切分,得到所有单词的列表
        val strList = stringList.flatMap(_.split(" "))
        println(strList)
    
        // 对相同的单词进行分组处理
        // println(strList.groupBy(_)) // 这里不能直接这样写,编译器报错了
        /**
         * missing parameter type for expanded function ((<x$2: error>) => strList.groupBy(x$2))
         * println(strList.groupBy(_))
         */
        val groupMap = strList.groupBy(el => el)
        println(groupMap)
    
        // 对Map中的每个Value取长度,得到每个单词的个数
        val groupMap2 = groupMap.map(tp => (tp._1, tp._2.length))
        println(groupMap2)
    
        // map转List 排序取前3
        val sortedList = groupMap2.toList.sortWith(_._2 > _._2).take(3)
        println(sortedList)
      }
    }

    单词计数,复杂案例:

    package cn
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
    
        // 单词计数 复杂案例
        val stringList : List[(String, Int)] = List(
          ("hello", 1),
          ("hello world", 2),
          ("hello scala", 3),
          ("hello spark from scala", 4),
          ("hello flink from scala", 5)
        )
    
        // 展开成普通的集合
        val strList = stringList.map(tuple => (tuple._1.trim + " ") * tuple._2)
        println(strList)
    
        val finalList = strList
          .flatMap(_.split(" "))
          .groupBy(el => el)
          .map(tuple => (tuple._1, tuple._2.length))
          .toList
          .sortWith(_._2 > _._2)
          .take(3)
        println(finalList)
    
        // 方式2 直接基于预计统计的结果进行转换
        val preCountList = stringList.flatMap( tuple => {
          val strings = tuple._1.split(" ")
          strings.map(word => (word, tuple._2))
        })
        println(preCountList)
    
        val preCountMap : Map[String, List[(String, Int)]] = preCountList.groupBy(_._1)
        println(preCountMap)
    
        // 这一段操作被Scala2.13版本弃用了,
        val countMap = preCountMap.mapValues(
          stringList => stringList.map(_._2).sum
        )
        println(countMap) // 这段打印拿不到对象信息
    
        println(countMap.toList.sortWith(_._2 > _._2).take(3)) // 但是最后调用不影响
      }
    }

    队列操作:

    package cn
    
    import scala.collection.immutable.Queue
    import scala.collection.mutable
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
    
        // 队列
        val que = new mutable.Queue[String]() // 空字符串元素类型队列
        println(que)
        que.enqueue( // 入队操作
          "A",
          "B",
          "C",
          "D"
        )
        println(que)
    
        println(que.dequeue()) // 出列操作
        println(que)
        println(que.dequeue())
        println(que)
        println(que.dequeue())
        println(que)
        println(que.dequeue())
        println(que)
    
        // 不可变队列
        val que2:Queue[String] = Queue("C", "D", "E")
        val que3 = que2.enqueue("F")
        println(que3)
      }
    }

    并行集合:

    package cn
    
    import scala.collection.immutable.Queue
    import scala.collection.mutable
    
    object HelloScala {
      def main(args: Array[String]): Unit = {
    
        // 并行集合 多核优化
    //    val idxSeq = (1 to 100).map(i => {
    //      s"currThreadName = ${Thread.currentThread.getName}, currThreadId = ${Thread.currentThread.getId}"
    //    })
    //    println(idxSeq)
    
    //    val idxSeq = (1 to 100).par.map(i => { // 这一段并行集合的已经不能使用了?
    //      s"currThreadName = ${Thread.currentThread.getName}, currThreadId = ${Thread.currentThread.getId}"
    //    })
    //    println(idxSeq)
      }
    }
  • 相关阅读:
    [CSP-S模拟测试]:影子(并查集+LCA)
    [CSP-S模拟测试]:夜鹰与玫瑰(数学)
    [CSP-S模拟测试]:抛硬币(DP)
    [CSP-S模拟测试]:影魔(树状数组+线段树合并)
    [CSP-S模拟测试]:队长快跑(DP+离散化+线段树)
    [CSP-S模拟测试]:玄学题/c(数学)
    [CSP-S模拟测试]:卡常题/b(基环树+DP)
    [CSP-S模拟测试]:工业题/a(数学)
    BZOJ5297 [Cqoi2018]社交网络 【矩阵树定理】
    BZOJ5300 [Cqoi2018]九连环 【dp + 高精】
  • 原文地址:https://www.cnblogs.com/mindzone/p/15019017.html
Copyright © 2020-2023  润新知