zoukankan      html  css  js  c++  java
  • Scala 学习 -- 其他集合类学习

    Scala 学习 -- 其他集合类学习

    一、序列

    列表缓冲 ListBuffer

    List类提供对列表头部快速访问,尾部访问并不高效。使用List类在尾部追加元素往往通过reverse,表头添加, reverse实现。

    通过ListBuffer可以简单实现。ListBuffer是一个可变对象,包含在scala.collection.mutable包中。ListBuffer提供了常量的向后追加和向前追加的方法,使用+=向后追加元素,使用+=:向前追加元素。ListBuffer优于List的另一个原因是防止可能出现的栈溢出。

    scala> import scala.collection.mutable.ListBuffer
    import scala.collection.mutable.ListBuffer
    
    scala> val buf = new ListBuffer[Int]
    buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
    
    scala> buf += 1
    res0: buf.type = ListBuffer(1)
    
    scala> buf += 2
    res1: buf.type = ListBuffer(1, 2)
    
    scala> 99 +=: buf
    res3: buf.type = ListBuffer(99, 1, 2)
    
    scala> buf
    res4: scala.collection.mutable.ListBuffer[Int] = ListBuffer(99, 1, 2)
    
    scala> buf.toList
    res5: List[Int] = List(99, 1, 2)
    

    数组缓冲 ArrayBuffer

    除额外从序列头部或者尾部添加移除元素外与数组基本一致。所有Array操作会稍慢,添加移除平均而言为常量时间,偶尔为线性时间,需要不时地分配新的数组来保存缓冲的内容。

    scala> import scala.collection.mutable.ArrayBuffer
    import scala.collection.mutable.ArrayBuffer
    
    scala> val buf = new ArrayBuffer[Int]()
    buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
    
    scala> buf += 12
    res6: buf.type = ArrayBuffer(12)
    
    scala> buf += 15
    res7: buf.type = ArrayBuffer(12, 15)
    
    scala> buf += 18
    res8: buf.type = ArrayBuffer(12, 15, 18)
    
    scala> buf -= 12
    res9: buf.type = ArrayBuffer(15, 18)
    
    scala> buf.length
    res10: Int = 2
    

    字符串(StringOps)

    Predef定义一个从String到StringOps的隐式方法,将任何字符串当作序列来处理。

    二、集和映射

    使用“Set”或“Map”时,默认得到一个不可变对象。可通过显示一次引入,改变为显式版本。这样的访问便利是通过Predef对象完成,每个对象内容在每个Scala源文件中隐式地引入。

    object Predef{
     type Map[A,+B] = collection.immutable.Map[A,B]
     type Set[A] = collection.immutable.Set[A]
     val Map = collection.immutable.Map
     val Set = collection.immutable.Set
     //...
    }
    

    集的关键特征在于它们会确保同一时刻,以 == 为标准,集里的每个对象都最多出现一次。

    //集的基本操作
    //创建一个不可变集
    scala> val nums = Set(1, 2, 3)
    nums: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
    
    //添加一个元素
    scala> nums + 5
    res12: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 5)
    
    //移除一个元素
    scala> nums - 3
    res14: scala.collection.immutable.Set[Int] = Set(1, 2)
    
    //添加多个元素
    scala> nums ++ List(5,6)
    res15: scala.collection.immutable.Set[Int] = HashSet(5, 1, 6, 2, 3)
    
    //移除多个元素
    scala> nums -- List(1,2)
    res16: scala.collection.immutable.Set[Int] = Set(3)
    
    //获取两个集合的交集
    scala> nums & Set(1,3,5,7)
    res17: scala.collection.immutable.Set[Int] = Set(1, 3)
    
    //返回集的大小
    scala> nums.size
    res18: Int = 3
    
    //检查是否包含
    scala> nums.contains(3)
    res19: Boolean = true
    
    //让可变集易于访问
    import scala.collection.mutable
    
    //创建一个空的可变集
    scala> val words = mutable.Set.empty[String]
    words: scala.collection.mutable.Set[String] = HashSet()
    
    //添加一个元素
    scala> words += "the"
    res20: words.type = HashSet(the)
    
    //移除一个元素
    scala> words -= "the"
    res21: words.type = HashSet()
    
    //添加多个元素
    scala> words ++= List("do","re","mi")
    res22: words.type = HashSet(re, do, mi)
    
    //移除多个元素
    scala> words --= List("do","re")
    res23: words.type = HashSet(mi)
    
    //清除所有元素
    scala> words.clear
    
    scala> words
    res25: scala.collection.mutable.Set[String] = HashSet()
    

    默认的集

    对于可变集合,scala.collection.mutable.Set()内部使用hash表,返回scala.collection.mutable.HashSet

    对于不可变集合,情况稍复杂。对于少于五个元素的集,有专门特定大小的类以此达到最好的性能。对于大于等于五个元素的集,使用哈希字典树(hash trie)实现。

    元素个数 实现
    0 scala.collection.immutable.EmptySet
    1 scala.collection.immutable.Set1
    2 scala.collection.immutable.Set2
    3 scala.collection.immutable.Set3
    4 scala.collection.immutable.Set4
    5或更多 scala.collection.immutable.HashSet

    注:

    Trie树, 字典树, 哈希树变种,是一种用于快速检索的多叉树结构,应用于统计和排序大量字符串。

    核心思想:以空间换时间,利用字符串公共前缀来降低查询时间开销以达到提高效率的目的。

    优点:最大限度减少无谓字符串比较,查询效率较哈希表高

    缺点:内存消耗非常大

    三个基本特性:

    1. 根节点不包含字符,除根节点外每一个节点只包含一个字符。
    2. 从根节点到某一结点,路径上经过的字符连接起来,为该节点对应的字符串。
    3. 每个节点的所有子节点包含字符都不相同

    插入过程:

    ​ 对于一个单词,从根开始,沿着单词的各个字母所对应的树中节点分支向下走,直至单词遍历完,将最后节点标记为红色,表示该单词已插入Trie树。

    查找过程:

    1. 从根节点开始一次搜索
    2. 取得要查找的关键词的第一个字母,并根据字母选择对应子树转入建索
    3. 同上一步方法,前进一层检索
    4. 在某个节点处,关键词的所有字母都被取出,则读取附在该节点上的信息,查找完成。

    排序集

    Scala集合类中提供了SortedSet特质,被TreeSet类实现,实现通过红黑树来保持元素或键的顺序。具体顺序由Ordered特质决定,集的元素类型必须混入或能够被隐式转换成Ordered。

    scala> import scala.collection.immutable.TreeSet
    import scala.collection.immutable.TreeSet
    
    scala> val ts = TreeSet(2,1,4,3,6,5,9,7,8)
    ts: scala.collection.immutable.TreeSet[Int] = TreeSet(1, 2, 3, 4, 5, 6, 7, 8, 9)
    
    scala> val cs = TreeSet("f","u","n")
    cs: scala.collection.immutable.TreeSet[String] = TreeSet(f, n, u)
    

    可变与不可变集选择

    ​ 不可变集较可变集而言,具有以下优点:

    1. 易于推敲
    2. 元素不多的情况下,不可变集合通常较可变集合存储更为紧凑

    不可变集与可变集相互转换

    1. 不可变集 => 可变集 :Scala提供了一个变通的解读,只要看到a += b而a并不支持名为+=的方法,Scala将尝试将他解读为 a = a + b。【注:声明为var】

    2. 可变集 <=> 不可变集:使用empty创建一个新类型的空集合,根据集合类型,使用++或++=方法添加新元素。

    集合的初始化

    1. 常见的方式:将初始元素传入所选集合的伴生对象的工厂方法
    2. 特殊方式:用别的集合初始化当前集合
    scala> val colors = List("blue", "yellow", "red", "green")
    colors: List[String] = List(blue, yellow, red, green)
    
    scala> import scala.collection.immutable.TreeSet
    import scala.collection.immutable.TreeSet
    
    scala> val treeset = TreeSet(colors)
                                ^
           error: No implicit Ordering defined for List[String].
    
    scala> val treeset = TreeSet[String]() ++ colors
    treeset: scala.collection.immutable.TreeSet[String] = TreeSet(blue, green, red, yellow)
    

    集转换成数组或列表

    转换成列表或数组通常需要将集合的所有元素做拷贝,对于大型集合来说这么做可能比较费时,若集合本来元素不多,拷贝带来的性能开销并不高。

    scala> treeset.toList
    res1: List[String] = List(blue, green, red, yellow)
    
    scala> treeset.toArray
    res2: Array[String] = Array(blue, green, red, yellow)
    

    映射

    映射特质是对集中的每个元素关联一个值。创建映射时,必须给出两个类型。第一个类型是针对映射的键,第二个类型是针对映射的值。

    //映射的常用操作
    //创建一个不可变映射
    scala> val nums = Map("i" -> 1, "li" -> 2)
    nums: scala.collection.immutable.Map[String,Int] = Map(i -> 1, li -> 2)
    
    //添加一个条目
    scala> nums + ("vi" -> 6)
    res3: scala.collection.immutable.Map[String,Int] = Map(i -> 1, li -> 2, vi -> 6)
    
    //移除一个条目
    scala> nums - "li"
    res5: scala.collection.immutable.Map[String,Int] = Map(i -> 1)
    
    //添加多个条目
    scala> nums ++ List("iii" -> 3, "v" -> 5)
    res6: scala.collection.immutable.Map[String,Int] = Map(i -> 1, li -> 2, iii -> 3, v -> 5)
    
    //移除多个条目
    scala> nums -- List("i","li")
    res7: scala.collection.immutable.Map[String,Int] = Map()
    
    //返回映射的大小
    scala> nums.size
    res8: Int = 2
    
    //检查是否包含
    scala> nums.contains("li")
    res9: Boolean = true
    
    //获取指定键的值
    scala> nums("li")
    res10: Int = 2
    
    //返回所有的键
    scala> nums.keys
    res12: Iterable[String] = Set(i, li)
    
    //以集的形式返回所有的键
    scala> nums.keySet
    res1: scala.collection.immutable.Set[String] = Set(i, li)
    
    // 返回所有的值
    scala> nums.values
    res2: Iterable[Int] = View(<not computed>)
    
    //表示映射是否为空
    scala> nums.isEmpty
    res3: Boolean = false
    
    //让可变集合便于访问
    import scala.collection.mutable
    
    //创建一个空的可变映射
    scala> val words = mutable.Map.empty[String,Int]
    words: scala.collection.mutable.Map[String,Int] = HashMap()
    
    //添加一个映射
    scala> words += ("one" -> 1)
    res4: words.type = HashMap(one -> 1)
    
    //移除一个映射
    scala> words -= "one"
    res5: words.type = HashMap()
    
    //添加多个映射
    scala> words ++= List("one"->1, "two"->2, "three"->3)
    res6: words.type = HashMap(one -> 1, two -> 2, three -> 3)
    
    //移除多个映射
    scala> words --= List("one", "two")
    res8: words.type = HashMap(three -> 3)
    

    默认映射

    与集类似,对于可变映射而言,scala.collection.mutable.Map()工厂方法返回的是一个scala.collection.mutable.HashMap。

    对于不可变映射,也与集类似。

    元素个数 实现
    0 scala.collection.immutable.EmptyMap
    1 scala.collection.immutable.Map1
    2 scala.collection.immutable.Map2
    3 scala.collection.immutable.Map3
    4 scala.collection.immutable.Map4
    5或更多 scala.collection.immutable.HashMap

    排序映射

    与集类似,Scala集合类中提供了SortedMap特质,被TreeMap类实现,实现通过红黑树来保持元素或键的顺序。具体顺序由Ordered特质决定,集的元素类型必须混入或能够被隐式转换成Ordered。

    scala> val treemap = TreeMap(1->"one", 3->"three", 2->"two")
    treemap: scala.collection.immutable.TreeMap[Int,String] = TreeMap(1 -> one, 2 -> two, 3 -> three)
    

    可变映射与不可变映射的相互转换

    与可变集和不可变集相互转换类似,映射间转换也采用类似方法。

    scala> import scala.collection.mutable
    import scala.collection.mutable
    
    scala> val muta = mutable.Map("i"->1, "ii"->2)
    muta: scala.collection.mutable.Map[String,Int] = HashMap(ii -> 2, i -> 1)
    
    scala> val immu = Map.empty ++ muta
    immu: scala.collection.immutable.Map[String,Int] = Map(ii -> 2, i -> 1)
    

    三、元组

    元组

    元组将一组固定个数的条目组合在一起,作为整体传递。元组可以持有不同类型的对象。常用场景为从方法返回多个值。访问元素的数组,可以用_1访问第一个元素, _2访问第二个元素。

    四、计数例子

    import scala.collection.mutable
    object counter {
      def main(args: Array[String]): Unit = {
        val text = "See Spot run. Run, Spot, Run!"
        val ans = countWords(text)
        println(ans)
      }
    
      def countWords(text:String) = {
        val counts = mutable.Map.empty[String, Int]
        for (rawWord <- text.split("[ !,.]+")){
          val word = rawWord.toLowerCase
          val oldCount = {
            if (counts.contains(word))  counts(word)
            else 0
          }
          counts += (word -> (oldCount+1))
        }
        counts
      }
    }
    
  • 相关阅读:
    ZT 安卓手机的安全性 prepare for Q
    ZT pthread_cleanup_push()/pthread_cleanup_pop()的详解
    <Lord don’t move that mountain>
    C++浅拷贝和深拷贝的区别
    001 Python简介 输入输出
    016 可等待计时器对象.6
    016 EventDemo 5
    016 事件内核对象4
    016 内核对象的Signal状态3
    016 句柄2
  • 原文地址:https://www.cnblogs.com/ganshuoos/p/13160688.html
Copyright © 2011-2022 走看看