scala编程第17章学习笔记(2)——集和映射

时间:2023-01-23 19:31:01

默认情况下在使用“Set”或“Map”的时候,获得的都是不可变对象。如果需要的是可变版本,需要先写明引用。

如果同一个源文件中既要用到可变版本,也要用到不可变版本的集合或映射,方法之一是引用包含了可变版本的包名:

scala> import scala.collection.mutable
import scala.collection.mutable

与以往一样, 不可变集可以用Set指代,但现在还可以用mutable.Set指代可变集。举例如下:

scala> val mutaSet = mutable.Set(1, 2, 3)
mutaSet: scala.collection.mutable.Set[Int] = Set(1, 2, 3)

使用集

集的关键特性在于它可以对使用对象的==操作检查,确保在任何时候每个对象只在集中保留最多一个副本。例如,我们可以用集对字符串不同单词计数。

如果指定空格和标点符号为单词的分隔符,String的split方法可以把字符串分割成单词。正则表达式“[  ! , .]“足以完成该功能:它表明字符串应该在每个存在一到多个空格或标点符号的地方分割开来:

scala> val text = "See Spot run. Run, Spot. Run!"
text: String = See Spot run. Run, Spot. Run! scala> val wordsArray = text.split("[ !,.]+")
wordsArray: Array[String] = Array(See, Spot, run, Run, Spot, Run)

要对不同的单词计数,可以先把它们变成同样的大小写然后加到集中。由于集不能重复添加,因此不同的单词只在集中出现一次。首先,可以使用Set伴生对象提供的empty方法创建空集:

scala> val words = mutable.Set.empty[String]
words: scala.collection.mutable.Set[String] = Set()

然后,用for表达式枚举所有的单词,分别把它们转换为小写字母形式,然后使用+=操作符添加到可变集中:

scala> for (word <- wordsArray)
words += word.toLowerCase scala> words
res2: scala.collection.mutable.Set[String] = Set(see, run, spot)

使用映射

映射可以用来把值与集合中的元素联系起来。映射的使用与数组接近,只是你可以用任何类型的键,而不仅仅是使用从0开始计数的整数做索引。如果引用了scala.collection.mutable包,你还可以创建空的可变映射:

scala> val map = mutable.Map.empty[String, Int]
map: scala.collection.mutable.Map[String,Int] = Map()

映射中的条目设置与数组中的类似:

scala> map("hello") = 1

scala> map("there") = 2

scala> map
res5: scala.collection.mutable.Map[String,Int] = Map(hello -> 1, there -> 2)

类似的,读取映射和读取数组也是一样的:

scala> map("hello")
res6: Int = 1

把上面的例子放在一起,就有了下面对字符串中单词出现次数做计数的方法:

scala> 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
| }
countWords: (text: String)scala.collection.mutable.Map[String,Int] scala> countWords("See Spot run! Run, Spot. Run!")
res7: scala.collection.mutable.Map[String,Int] = Map(spot -> 2, see -> 1, run ->
3)

有序的集和映射
scala的集合库提供了SortedSet和SortedMap特质。这两个特质分别由类TreeSet和TreeMap实现,他们都使用了红黑树有序地保存元素(TreeSet类)或键(TreeMap类)。具体的顺序取决于Ordered特质,集的元素类型或映射的键类型必须要么混入,要么能够隐式地转换成Ordered特质。这些类只有不可变类型的版本。下面是TreeSet的例子:

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

下面是TreeMap的例子:

scala> import scala.collection.immutable.TreeMap
import scala.collection.immutable.TreeMap scala> var tm = TreeMap(3 -> 'x', 1 -> 'x', 4 -> 'x')
tm: scala.collection.immutable.TreeMap[Int,Char] = Map(1 -> x, 3 -> x, 4 -> x) scala> tm += (2 -> 'x') scala> tm
res9: scala.collection.immutable.TreeMap[Int,Char] = Map(1 -> x, 2 -> x, 3 -> x,
4 -> x)

同步的(Synchronized)集和映射

如果需要线程安全的映射,可以把SynchronizedMap特质混入到你想要的特质类实现中。下面是一个吧SynchronizedMap混入HashMap的例子:

import scala.collection.mutable.{Map, SynchronizedMap, HashMap}

object MapMaker {
def makeMap: Map[String, String] = {
new HashMap[String, String] with SynchronizedMap[String, String]{
override def default(key: String) =
"Why do you want to know?"
}
}
}

如果你请求映射返回与特定键关联的值,而该键的映射实际不存在,默认你将得到NoSuchElementException。然而如果你定义了新的映射类并重载了default方法,那么这个新的映射将在查询不存在的键时返回default方法的返回值。根据上面的代码,由编译器构造的合成HashMap子类将在查询不存在的键时返回”Why do you want to know?"。
下面的例子演示了在解释器中,单线程访问映射的情况:

scala> import scala.collection.mutable.{Map, SynchronizedMap, HashMap}
import scala.collection.mutable.{Map, SynchronizedMap, HashMap} scala> object MapMaker {
| def makeMap: Map[String, String] = {
| new HashMap[String, String] with SynchronizedMap[String, String]{
| override def default(key: String) =
| "Why do you want to know?"
| }
| }
| }
warning: there was one deprecation warning; re-run with -deprecation for details defined object MapMaker scala> val capital = MapMaker.makeMap
capital: scala.collection.mutable.Map[String,String] = Map() scala> capital ++ List("US" -> "Washington", "Paris" -> "France", "Japan" -> "To
kyo")
res10: scala.collection.mutable.Map[String,String] = Map(Paris -> France, Japan
-> Tokyo, US -> Washington) scala> capital("Japan")
res11: String = Why do you want to know? scala> capital += ("New Zealand" -> "Wellington")
res12: capital.type = Map(New Zealand -> Wellington) scala> capital("New Zealand")
res13: String = Wellington

你可以按照与创建同步映射类似的方法创建同步集。例如可以通过混入SynchronizedSet特质创建同步的HashSet,见下:

scala> import scala.collection.mutable
import scala.collection.mutable scala> val synchroSet =
| new mutable.HashSet[Int] with
| mutable.SynchronizedSet[Int]
warning: there was one deprecation warning; re-run with -deprecation for details synchroSet: scala.collection.mutable.HashSet[Int] with scala.collection.mutable.SynchronizedSet[Int] = Set()

scala编程第17章学习笔记(2)——集和映射的更多相关文章

  1. scala编程第17章学习笔记(3)

    可变(mutable)集合与不可变(immutable)集合 为了更易于完成不可变集合到可变集合的转换,或者反向转换,Scala提供了一些语法糖.纵使不可变集和映射并不支持真正的+=方法,Scala还 ...

  2. scala编程第17章学习笔记(4)——元组

    元组可以把固定数量的条目组合在一起以便于作为整体传送.不像数组或列表,元组可以保存不同类型的对象. 元组常用来返回方法的多个值.例如,下面的方法找到集合中的最长单词并返回它的索引: scala> ...

  3. scala编程第17章学习笔记(1)——集合类型

    列表 列表的初始化及对其首尾的访问: scala> val colors = List("red", "blue", "green") ...

  4. scala编程第16章学习笔记(3)——List类的高阶方法

    列表间映射:map.flatMap和foreach 1.xs map f 操作返回把函数f应用在xs的每个列表元素之后由此组成的新列表.如: scala> List(1, 2, 3) map ( ...

  5. scala编程第16章学习笔记(2)

    转换列表:toIterator, toArray,copyToArray List类的toArray方法将递归存放的列表转换为连续存放的数组 Array类的toList方法将连续存放的数组转换为递归存 ...

  6. scala编程第16章学习笔记(1)

    List列表的基本操作 head方法获得列表的第一个元素 tail方法获得列表除第一个元素之外的其它元素 isEmpty:判断列表是否为空,空的话返回真 last:获得列表最后一个元素 init:获得 ...

  7. scala编程第19章学习笔记(1)——类型参数化

    一.queues函数式队列 函数式队列是一种具有以下三种操作方式的数据结构: head 返回队列的第一个元素. tail 返回除第一个元素之外的队列. scala> import scala.c ...

  8. scala编程第18章学习笔记——有状态的对象

    银行账号的简化实现: scala> class BankAccount{ | private var bal: Int = 0 | def balance: Int = bal | def de ...

  9. scala编程第16章学习笔记(4)——List对象的方法

    通过元素创建列表:List.apply List(1, 2, 3) 等价于List.apply(1, 2, 3): scala> List.apply(1, 2, 3) res0: List[I ...

随机推荐

  1. Office 365 – SharePoint 2013 Online 与Office相关的应用

    1.在Office 365首页,点击在PC上安装Office,如下图: 2.会下载一个安装向导程序,如下图: 3.安装Office向导,如下图: 4.安装完毕以后,发现开始菜单多出Office 201 ...

  2. Unix-Linux编程实践 学习点滴

    1.结构体最后定义一个char p[0]有什么作用 2. 3. 4. 1.结构体最后定义一个char p[0] 有什么作用 这是个广泛使用的常见技巧,常用来构成缓冲区.比起指针,用空数组有这样的优势: ...

  3. web app开发中 iPhone、iPad默认按钮样式问题

    webapp开发过程中,用html5+css3很方便,而且可以很方便的编译到Android ios等不同平台,但是ios需要单独处理一下,不然会出现一些想象不到的问题.下面就介绍一下各种问题的解决方法 ...

  4. ural 1203&period; Scientific Conference(动态规划)

    1203. Scientific Conference Time limit: 1.0 second Memory limit: 64 MB Functioning of a scientific c ...

  5. Nginx 进程间如何共享内存

    L:37 Nginx 针对多进程用的是自旋锁(占用共享内存时间比较短的情况下否则可能会影响性能)注:自旋锁是不停的请求共享内存 而原先的信号量是等待占用者释放后通知等待的进程

  6. spring中的&commat;Bean是否一定要与&commat;Configuration一起用

        版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/little_newBee/article/details/80383691 在使用sprin ...

  7. NOI Day2线上同步赛崩盘记

    Preface 蒟蒻愉快的NOI线上赛Day2之行,不过因为太菜就凉了 这次由于策略&&网络的问题,最后两题都没有交,结果就靠T1稳住拿了75分就回家了. 我真是太菜了. 屠龙勇士 首 ...

  8. &lbrack;Spark&rsqb;&lbrack;Python&rsqb;RDD flatMap 操作例子

    RDD flatMap 操作例子: flatMap,对原RDD的每个元素(行)执行函数操作,然后把每行都“拍扁” [training@localhost ~]$ hdfs dfs -put cats. ...

  9. OD之修改文件标题&lpar;一&rpar;

    OD是逆向工程中的一个重要工具,逆向工程调试说明具体请参考:百度百科,OD介绍,当然就我了解而言,俗话就是破解软件,市面上的什么破解版,精简版啥的基本都是通过这种技术的,但是这并不能一概而论说逆向工程 ...

  10. javaScript操作数组的常用方法

    map(映射), reduce(规约), forEach(遍历), filter(过滤),它们都是高阶函数,都是以传入不同的函数来以不同的方式操作数组元.ie都不支持 判断是否为数组 Array.is ...