Scala学习之——几种常用数据结构(Array、List、Set、Tuple、Map)

时间:2022-01-21 21:41:44

1 使用类型参数化数组(Array)

Scala里使用new实例化对象,也可以称之为类实例。实例化过程中,可以用值和类型使对象参数化(parameterize)。参数化的意思是指在创建实例的同时完成对它的“设置”。使用值参数化实例可以通过把值传递给构造器的圆括号来实现。例如,下面的代码将创建值参数为“12345”的java.math.BigInteger实例:

scala> val big = new java.math.BigInteger("12345")
big: java.math.BigInteger = 12345

使用类型参数化实例可以通过把一个或更多类型指定到基础类型后的方括号里来实现。如在下面的例子中,greetStrings的类型是Array[String](字符串数组),并且由于创建数组的值参数为3,即代表其初始长度为3。

scala> val greetStrings = new Array[String](3)
greetStrings: Array[String] = Array(null, null, null)

scala> greetStrings(0) = "Hello"
scala> greetStrings(1) = ","
scala> greetStrings(2) = "world!\n"
scala> for(i <- 0 to 2)
| print(greetStrings(i))
Hello,world!

注意:Scala的数组是通过索引值加圆括号进行访问的,而不是像Java那样的把索引值放在方括号里。所以数组的首个元素是greetStrings(0),而不是greetString[0]。
为什么在Scala中,要用圆括号访问数组而不是方括号?与Scala的其他类一样,数组也只是类的实例。用括号传递给变量一个或多个值参数时,Scala会把它转换为对apply方法的调用。于是greetStrings(i)转换成greetStrings.apply(i)。所以Scala里访问数组的元素也不过是跟其他的一样的方法调用。这个原则不是只对于数组:任何对于对象的值参数应用都将被转换为对apply方法的调用。当然前提是这个类型实际定义过apply方法。
除了上面的带有参数类型的、长度、使用new关键字初始化的

2 列表(List)

Scala 列表类似于数组,它们所有元素的类型都相同(为同一种基本数据类型,或者Any——可以为几种基本数据类型的组合),但是与数组也有所不同:列表是不可变的,值一旦被定义了就不能改变,其次列表 具有递归的结构(也就是链接表结构)而数组不是。

2.1 列表的几种常见类型

列表的元素类型 T 可以写成 List[T]。例如,以下列出了多种类型的列表:

scala> val site:List[String] = List("Runoob", "Google", "Baidu")    //字符串列表
site: List[String] = List(Runoob, Google, Baidu)

scala> val nums:List[Int] = List(1, 2, 3, 4) //整型列表
nums: List[Int] = List(1, 2, 3, 4)

scala> val empty: List[Nothing] = List() //空列表
empty: List[Nothing] = List()

scala> val b = List("abc", 1, 'a') //多种基本类型组合在一起的Any类型的列表
b: List[Any] = List(abc, 1, a)

scala> var dim:List[List[Int]] = Nil //定义二维列表
dim: List[List[Int]] = List()

scala> dim = dim:::List(List(1, 2, 3)) //多个列表串联在一起
dim: List[List[Int]] = List(List(1, 2, 3))

scala> dim = dim:::List(List(4, 5, 6))
dim: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6))

2.2 构造列表的几种方式

  1. 通过给定列表的类型及值的方式初始化列表。
scala> val numList = List[Int](1, 3, 5)                     //初始化整型列表
numList: List[Int] = List(1, 3, 5)

scala> val nameList:List[String] = List("Bob", "Tom", "Jim")//初始化字符串列表
nameList: List[String] = List(Bob, Tom, Jim)

scala> numList(0) //通过下标取出列表中的第1个元素(列表下标从0开始)
res17: Int = 1

scala> nameList(2) //通过下标取出列表中的第3个字符串(下标为2)
res20: String = Jim
  1. 构造列表的两个基本单位是 Nil 和 :: ,其中Nil 也可以表示为一个空列表。
    上面的实例也可以写成如下所示:
scala> val site = "Bing"::("Google"::("Baidu"::Nil))
site: List[String] = List(Bing, Google, Baidu)

scala> val nums = 1 :: (2 :: (3 :: (4 :: Nil)))
nums: List[Int] = List(1, 2, 3, 4)

scala> val empty = Nil
empty: scala.collection.immutable.Nil.type = List()

scala> val dim = (1 :: (0 :: (0 :: Nil))) :: (0 :: (1 :: (0 :: Nil))) :: (0 :: (0 :: (1 :: Nil))) ::Nil
dim: List[List[Int]] = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))
  1. 可以使用 :::运算符或 List.:::()方法或 List.concat() 方法来连接两个或多个列表。
//运用::运算符构造单个的列表
scala> val site1 = "Runoob" :: ("Google" :: ("Baidu" :: Nil))
site1: List[String] = List(Runoob, Google, Baidu)

scala> val site2 = "Facebook" :: ( "Taobao" :: Nil)
site2: List[String] = List(Facebook, Taobao)

//*使用:::运算符将两个列表连接成一个列表,操作符++也可以将两个列表连接(合并)为一个列表*
scala> var fruit = site1 ::: site2
fruit: List[String] = List(Runoob, Google, Baidu, Facebook, Taobao)

//使用list1.:::(list2)方法将列表list1和列表list2连接在一起
scala> fruit = site1.:::(site2)
fruit: List[String] = List(Facebook, Taobao, Runoob, Google, Baidu)

//使用List.concat(list1, list2)将列表list1和list2连接在一起
scala> fruit = List.concat(site1, site2)
fruit: List[String] = List(Runoob, Google, Baidu, Facebook, Taobao)

scala> val num1 = List(1, 2, 3)
num1: List[Int] = List(1, 2, 3)

scala> val num2 = List(4, 5, 6)
num2: List[Int] = List(4, 5, 6)

scala> val num = num1 ::: num2
num: List[Int] = List(1, 2, 3, 4, 5, 6)

2.3 列表的基本操作

2.3.1 获取列表head和tail

Scala列表有三个基本操作:
- head 返回列表第一个元素;
- tail 返回一个列表,包含除了列表中第一元素之外的其他元素;
- isEmpty 在列表为空时返回true。

对于Scala列表的任何操作都可以使用这三个基本操作来表达。实例如下:

scala> val site = List("Runoob", "Google", "Baidu")
site: List[String] = List(Runoob, Google, Baidu)

scala> site.head //获取列表中的第一个元素
res10: String = Runoob

scala> site.tail //获取列表中第一个元素之外的所有元素,返回的还是一个列表
res11: List[String] = List(Google, Baidu)

scala> site.tail.tail
res12: List[String] = List(Baidu)

scala> site.tail.tail.toString //将获取的列表转换为字符串
res13: String = List(Baidu)

scala> site.tail.tail.head //获取列表res12的第一个元素
res14: String = Baidu

scala> val nums = Nil //定义空列表nums
nums: scala.collection.immutable.Nil.type = List()

scala> nums.isEmpty //判断列表nums是否为空,为空则返回true
res15: Boolean = true

2.3.2 List.fill()

可以使用 List.fill(n)(list) 方法来创建一个指定重复数量(n次)的元素列表(list)

scala> val site = List.fill(3)("Baidu")                         //重复Baidu3次
site: List[String] = List(Baidu, Baidu, Baidu)

scala> val num = List.fill(6)(8) //重复8一共6
num: List[Int] = List(8, 8, 8, 8, 8, 8)

scala> val name = List.fill(3)(List("Bob", "Tom", "Jan")) //列表中重复列表List("Bob", "Tom", "Jan")3
name: List[List[String]] = List(List(Bob, Tom, Jan), List(Bob, Tom, Jan), List(Bob, Tom, Jan))

scala> val name = List.fill(3)("Bob", "Tom", "Jan") //列表中重复元组("Bob", "Tom", "Jan")3
name: List[(String, String, String)] = List((Bob,Tom,Jan), (Bob,Tom,Jan), (Bob,Tom,Jan))

2.3.3 List.tabulate()

List.tabulate() 方法是通过给定的函数来创建列表。方法的第一个参数为元素的数量,可以是二维的,第二个参数为指定的函数,通过指定的函数计算结果并返回值,插入到列表中,起始值为 0,实例如下:

scala> val squares = List.tabulate(6)(n => n*n)
squares: List[Int] = List(0, 1, 4, 9, 16, 25)

scala> val mul = List.tabulate(4, 5)(_ * _)
mul: List[List[Int]] = List(List(0, 0, 0, 0, 0), List(0, 1, 2, 3, 4), List(0, 2, 4, 6, 8), List(0, 3, 6, 9, 12))

scala> def f(n: Int) = n * n
f: (n: Int)Int
scala> val n = List.tabulate(6)(f)
n: List[Int] = List(0, 1, 4, 9, 16, 25)

scala> val n = List.tabulate(3)(1 to 10)
n: List[Int] = List(1, 2, 3)

2.3.4 List.reverse

List.reverse 用于将列表的顺序反转,实例如下:

scala> val n = List.tabulate(3)(1 to 10)
n: List[Int] = List(1, 2, 3)
scala> n.reverse
res21: List[Int] = List(3, 2, 1)

scala> val name = List("Bob", "Tom", "Jim")
name: List[String] = List(Bob, Tom, Jim)
scala> name.reverse
res24: List[String] = List(Jim, Tom, Bob)

2.4 Scala List 常用方法

下表列出了 Scala List 常用的方法:
序号 方法及描述
(1) def +:(elem: A): List[A]
+:方法在列表开头为列表添加元素。可以添加单个元素,也可以在列表中添加(嵌套)列表。注意:该方法返回的是列表,所以两个列表list1和list2通过调用+:方法(list1 +: list2)之后,其结果为列表(嵌套列表)。

scala> val x = List(1)
x: List[Int] = List(1)

scala> val y = 2 +: x
y: List[Int] = List(2, 1)

scala> println(x)
List(1)

scala> val x = List(1,3)
x: List[Int] = List(1, 3)

scala> val y = 2 +: x
y: List[Int] = List(2, 1, 3)

scala> val y = (2,5) +: x
y: List[Any] = List((2,5), 1, 3)

scala> val y = List(2,5) +: x
y: List[Any] = List(List(2, 5), 1, 3)

scala> val z = x +: y
z: List[Any] = List(List(1, 3), List(2, 5), 1, 3)

(2) def ::(a : A): List[A]
在列表开头添加元素

scala> val l2 = 3 :: l1
l2: List[Int] = List(3, 1, 2)

(3) def :::(prefix: List[A]): List[A]
在列表开头添加指定列表的元素
(4) def :+(elem: A): List[A]
在列表尾部追加元素。
scala> val a = List(1)
a: List[Int] = List(1)

scala> val b = a :+ 2
b: List[Int] = List(1, 2)

scala> println(a)
List(1)
(5) def addString(b: StringBuilder): StringBuilder
将列表的所有元素添加到 StringBuilder

scala> val buffer = new StringBuilder()
buffer: StringBuilder =

scala> val listString = List("Tom", "Jim", "Rose")
listString: List[String] = List(Tom, Jim, Rose)

scala> val bs = listString.addString(buffer)
bs: StringBuilder = TomJimRose

(6) def addString(b: StringBuilder, sep: String): StringBuilder
将列表的所有元素添加到 StringBuilder,并指定分隔符

scala> val buffer1 = new StringBuilder()
buffer1: StringBuilder =

scala> val listString = List("Tom", "Jim", "Rose")
listString: List[String] = List(Tom, Jim, Rose)

scala> val bs1 = listString.addString(buffer1, ",")
bs1: StringBuilder = Tom,Jim,Rose

(7) def apply(n: Int): A
通过列表索引获取元素

scala> val listString = List("Tom", "Jim", "Rose")
listString: List[String] = List(Tom, Jim, Rose)

scala> listString.apply(0)
res27: String = Tom

(8) def contains(elem: Any): Boolean
检测列表中是否包含指定的元素

scala> val listString = List("Tom", "Jim", "Rose")
listString: List[String] = List(Tom, Jim, Rose)

scala> listString.contains("Tom")
res28: Boolean = true

(9) def copyToArray(xs: Array[A], start: Int, len: Int): Unit
将列表的元素复制到数组中。

scala> val listString = List("Tom", "Jim", "Rose")
listString: List[String] = List(Tom, Jim, Rose)

scala> val arr = new Array[String](3)
arr: Array[String] = Array(null, null, null)

scala> listString.copyToArray(arr, 1,2)

scala> arr
res30: Array[String] = Array(null, Tom, Jim)

(10) def distinct: List[A]
去除列表的重复元素,并返回新列表

scala> val aList = List(1, 2, 3, 1, 2, 5, 2, 6, 8)
aList: List[Int] = List(1, 2, 3, 1, 2, 5, 2, 6, 8)

scala> val bList = aList.distinct
bList: List[Int] = List(1, 2, 3, 5, 6, 8)

scala> aList
res31: List[Int] = List(1, 2, 3, 1, 2, 5, 2, 6, 8)

(11) def drop(n: Int): List[A]
丢弃前n个元素,并返回新列表
(12) def dropRight(n: Int): List[A]
丢弃最后n个元素,并返回新列表

scala> aList
res33: List[Int] = List(1, 2, 3, 1, 2, 5, 2, 6, 8)

scala> val cList = aList.drop(2) //移除列表前两个元素,返回一个新列表,但不改变原来的列表
cList: List[Int] = List(3, 1, 2, 5, 2, 6, 8)

scala> aList
res34: List[Int] = List(1, 2, 3, 1, 2, 5, 2, 6, 8)

scala> aList.dropRight(2) //移除列表最后两个元素
res36: List[Int] = List(1, 2, 3, 1, 2, 5, 2)

(13) def dropWhile(p: (A) => Boolean): List[A]
从左向右丢弃元素,直到条件p不成立

(14) def endsWith[B](that: Seq[B]): Boolean
检测列表是否以指定序列结尾

scala> aList
res41: List[Int] = List(1, 2, 3, 1, 2, 5, 2, 6, 8)

scala> aList.endsWith(List(6, 8))
res43: Boolean = true

(15) def equals(that: Any): Boolean
判断是否相等

(16) def exists(p: (A) => Boolean): Boolean
判断列表中指定条件的元素是否存在。

判断l是否存在某个元素:
scala> l.exists(s => s == "Hah")
res7: Boolean = true

scala> val name = List("Tom", "Jim", "Mary")
name: List[String] = List(Tom, Jim, Mary)

scala> name.exists(s => s.contains("Tom") )
res48: Boolean = true

scala> name.exists(s => s.equals("Tom") )
res49: Boolean = true

scala> name.dropWhile(s => s.equals("Mary") )
res50: List[String] = List(Tom, Jim, Mary)

scala> name
res51: List[String] = List(Tom, Jim, Mary)

(17) def filter(p: (A) => Boolean): List[A]
输出符号指定条件的所有元素。

//过滤出长度为3的元素:
scala> name
res51: List[String] = List(Tom, Jim, Mary)
scala> name.filter(s => s.length == 3)
res52: List[String] = List(Tom, Jim)

(18)def forall(p: (A) => Boolean): Boolean
检测所有元素。

//例如:判断所有元素是否以"m"结尾:
scala> name
res51: List[String] = List(Tom, Jim, Mary)

scala> name.forall(s => s.endsWith("m"))
res53: Boolean = false

(19) def foreach(f: (A) => Unit): Unit
将函数应用到列表的所有元素

(20) def head: A
获取列表的第一个元素
(21) def indexOf(elem: A, from: Int): Int
从指定位置 from 开始查找元素elem第一次出现的位置,没有则返回-1(元素下标从0开始)。

scala> name
res59: List[String] = List(Tom, Jim, Mary)

scala> name.indexOf("Jom", 0)
res60: Int = -1

scala> name.indexOf("Jim", 0)
res61: Int = 1

(22) def init: List[A]
返回所有元素,除了最后一个

scala> name
res59: List[String] = List(Tom, Jim, Mary)

scala> name.init
res62: List[String] = List(Tom, Jim)

(23) def intersect(that: Seq[A]): List[A]
计算多个集合的交集(交集,即多个集合中交叉的部分,共同存在的元素)。

scala> val a = List(1, 3, 5, 7, 9, 2, 6, 8)
a: List[Int] = List(1, 3, 5, 7, 9, 2, 6, 8)

scala> val b = List(1, 2, 3 ,5, 6, 8,9)
b: List[Int] = List(1, 2, 3, 5, 6, 8, 9)

scala> a.intersect(b)
res63: List[Int] = List(1, 3, 5, 9, 2, 6, 8)

(24) def isEmpty: Boolean
检测列表是否为空

(25) def iterator: Iterator[A]
创建一个新的迭代器来迭代元素

scala> a
res66: List[Int] = List(1, 3, 5, 7, 9, 2, 6, 8)
scala> val iter = a.iterator
iter: Iterator[Int] = non-empty iterator
scala> while(iter.hasNext){
var ne = iter.next()
println(ne)
}
1
3
5
7
9
2
6
8

(26) def last: A
返回最后一个元素
(27) def lastIndexOf(elem: A, end: Int): Int
从指定的位置 end 开始查找元素elem最后出现的位置。
(28) def length: Int
返回列表长度
(29) def map[B](f: (A) => B): List[B]
通过给定的方法将所有元素重新计算

scala> a
res68: List[Int] = List(1, 3, 5, 7, 9, 2, 6, 8)

scala> a.map(x => x * x)
res71: List[Int] = List(1, 9, 25, 49, 81, 4, 36, 64)

(30) def max: A
查找最大元素
(31) def min: A
查找最小元素
(32) def mkString: String
列表所有元素作为字符串显示

(33) def mkString(sep: String): String
使用分隔符将列表所有元素作为字符串显示

scala> a
res72: List[Int] = List(1, 3, 5, 7, 9, 2, 6, 8)

scala> a.mkString
res73: String = 13579268

scala> a.mkString(",")
res74: String = 1,3,5,7,9,2,6,8

scala> a.mkString("[", ",", "]") //在列表的开头以[分隔,每个元素之间用英文逗号分隔,最后一个元素后用]分隔
res75: String = [1,3,5,7,9,2,6,8]

(34) def reverse: List[A]
列表反转
(35) def sorted[B >: A]: List[A]
列表排序
(36) def startsWith[B](that: Seq[B], offset: Int): Boolean
检测列表在指定位置是否包含指定序列
(37) def sum: A
计算集合元素之和
(38) def tail: List[A]
返回所有元素,除了第一个
(39) def take(n: Int): List[A]
提取列表的前n个元素
(40) def takeRight(n: Int): List[A]
提取列表的后n个元素

scala> a
res76: List[Int] = List(1, 3, 5, 7, 9, 2, 6, 8)

scala> a.take(6) //提取列表前6个元素
res77: List[Int] = List(1, 3, 5, 7, 9, 2)

scala> a.takeRight(3) //提取列表后3个元素
res78: List[Int] = List(2, 6, 8)

(41) def toArray: Array[A]
列表转换为数组
(42) def toBuffer[B >: A]: Buffer[B]
返回缓冲区,包含了列表的所有元素
(43) def toMap[T, U]: Map[T, U]
List 转换为 Map
(44) def toSeq: Seq[A]
List 转换为 Seq
(45) def toSet[B >: A]: Set[B]
List 转换为 Set
(46) def toString(): String
列表转换为字符串。

scala> a
res79: List[Int] = List(1, 3, 5, 7, 9, 2, 6, 8)

scala> a.toArray
res80: Array[Int] = Array(1, 3, 5, 7, 9, 2, 6, 8)

scala> a.toBuffer
res81: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 3, 5, 7, 9, 2, 6, 8)

scala> a.toSeq
res83: scala.collection.immutable.Seq[Int] = List(1, 3, 5, 7, 9, 2, 6, 8)

scala> a.toSet
res84: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 9, 2, 7, 3, 8)

scala> a.toString
res85: String = List(1, 3, 5, 7, 9, 2, 6, 8)

由于列表中,有多种添加元素或连接列表的方式,比如::、:::、+:、:+、++等,这些操作符使用的时候有些区别,注意仔细观察下面的示例:

scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)

scala> val list2 = List(5, 6, 7)
list2: List[Int] = List(5, 6, 7)

scala> val re = list ::: list2 //操作符:::将两个列表连接(合并)为一个列表
re: List[Int] = List(1, 2, 3, 5, 6, 7)

scala> val re1 = list +: list2 //操作符+:表示将一个元素或列表添加到大列表头部(加号在前,表示向前添加),操作符前边为列表就添加列表,为单个元素就添加元素;跟操作符之后数据的类型没关
re1: List[Any] = List(List(1, 2, 3), 5, 6, 7)
scala> val n1 = 4 +: list2
n1: List[Int] = List(4, 5, 6, 7)

scala> val re2 = list :+ list2 //操作符+:表示将一个元素或列表添加到大列表尾部(+号在后,表示向后追加),操作符后边为列表就添加列表,为单个元素就添加元素;跟操作符前的数据的类型没关
re1: List[Any] = List(1, 2, 3, List(5, 6, 7))

scala> val re13 = list ++ list2
re13: List[Int] = List(1, 2, 3, 5, 6, 7)

scala> val re13 = list :: list2 ////**操作符++也可以将两个列表连接(合并)为一个列表**
re13: List[Any] = List(List(1, 2, 3), 5, 6, 7)

3 集(Set)

Scala Set(集)是没有重复的对象集合,所有的元素都是唯一的。

3.1 可变与不可变Set

Scala 集合分为可变的和不可变的集合。
默认情况下,Scala 使用的是不可变集合,如果想要使用可变集,需要引用 scala.collection.mutable.Set 包。
默认引用 scala.collection.immutable.Set,不可变集合实例如下:

scala> val set = Set(1, 3, 5)               //初始化Set
set: scala.collection.immutable.Set[Int] = Set(1, 3, 5)

scala> println(set.getClass.getName) //获取变量set的类名
scala.collection.immutable.Set$Set3

scala> println(set.exists(_ % 2 == 0)) //检查Set中是否存在为偶数的元素
false

scala> println(set.drop(1)) //删除Set中的元素1
Set(3, 5)

scala> println(set.filter(_ > 3)) //过滤出来集合中大于3的元素
Set(5)

如果需要使用可变集合,那么需要先引入 scala.collection.mutable.Set:
import scala.collection.mutable.Set // 可以在任何地方引入 可变集合

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

scala> val mutableSet = Set(1, 3 ,5, 6, 8, 10)
mutableSet: scala.collection.mutable.Set[Int] = Set(1, 5, 6, 3, 10, 8)

scala> println(mutableSet.getClass.getName)
scala.collection.mutable.HashSet

scala> mutableSet.add(7) //add方法每次只能往Set中添加一个元素
res93: Boolean = true

scala> mutableSet
res94: scala.collection.mutable.Set[Int] = Set(1, 5, 6, 3, 10, 7, 8)

scala> mutableSet.remove(1)
res95: Boolean = true

scala> mutableSet += 4
res96: mutableSet.type = Set(5, 6, 3, 10, 7, 4, 8)

scala> mutableSet -= 10
res97: mutableSet.type = Set(5, 6, 3, 7, 4, 8)

注意: 虽然可变Set和不可变Set都有添加或删除元素的操作,但是有一个非常大的差别。对不可变Set进行操作,会产生一个新的set,原来的set并没有改变,这与List一样。 而对可变Set进行操作,改变的是该Set本身,与ListBuffer类似。

3.2 集合基本操作

3.2.1 Set的head、tail、isEmpty方法

Scala集合有三个基本操作:

  • head 返回集合第一个元素;
  • tail 返回一个集合,包含除了第一元素之外的其他元素;
  • isEmpty 判断集合是否为空,在集合为空时返回true。

对于Scala集合的任何操作都可以使用这三个基本操作来表达。实例如下:

scala> val site1 = Set("Google", "Baidu", "Facebook", "Taobao") 
site1: scala.collection.mutable.Set[String] = Set(Google, Baidu, Taobao, Facebook)

scala> val site2 = Set("Sina", "Amazon", "Jingdong")
site2: scala.collection.mutable.Set[String] = Set(Sina, Amazon, Jingdong)

scala> site1.head
res98: String = Google

scala> site1.tail
res99: scala.collection.mutable.Set[String] = Set(Baidu, Taobao, Facebook)

scala> site2.isEmpty
res100: Boolean = false

3.2.2 连接操作

可以使用 ++ 运算符或 set1.++(set2) 方法来将两个集合set1和set2连接起来组成一个新的Set,如果元素有重复的就会移除重复的元素。

scala> val site1 = Set("Google", "Baidu", "Facebook", "Taobao") 
site1: scala.collection.mutable.Set[String] = Set(Google, Baidu, Taobao, Facebook)

scala> val site2 = Set("Sina", "Amazon", "Jingdong")
site2: scala.collection.mutable.Set[String] = Set(Sina, Amazon, Jingdong)

scala> val site = site1 ++ site2
site: scala.collection.mutable.Set[String] = Set(Google, Sina, Baidu, Taobao, Amazon, Facebook, Jingdong)

scala> val sites = site1.++(site2)
sites: scala.collection.mutable.Set[String] = Set(Google, Sina, Baidu, Taobao, Amazon, Facebook, Jingdong)

3.2.3 min和max方法

可以使用 min 方法来查找集合中的最小元素,使用 max 方法查找集合中的最大元素。注意,字符及字符串类型的数据也可以较大大小,所以这样的集合也能获取最大最小值。

scala> val site1 = Set("Google", "Baidu", "Facebook", "Taobao") 
site1: scala.collection.mutable.Set[String] = Set(Google, Baidu, Taobao, Facebook)

scala> val site2 = Set("Sina", "Amazon", "Jingdong")
site2: scala.collection.mutable.Set[String] = Set(Sina, Amazon, Jingdong)

scala> val site = site1 ++ site2
site: scala.collection.mutable.Set[String] = Set(Google, Sina, Baidu, Taobao, Amazon, Facebook, Jingdong)

scala> site1.min
res101: String = Baidu

scala> site1.max
res102: String = Taobao

scala> val numSet = Set(1, 2, 3, 5, 6, 3, 2)
numSet: scala.collection.mutable.Set[Int] = Set(1, 5, 2, 6, 3) //Set集合中会自动去除重复的元素

scala> numSet.min
res103: Int = 1

scala> numSet.max
res104: Int = 6

3.2.4 交集

可以使用 set1.& (set2)方法或 set1.intersect(set2) 方法来查看两个集合set1和set2的交集元素。

scala> val num1 = Set(1, 3, 4, 5, 6 ,7)
num1: scala.collection.mutable.Set[Int] = Set(1, 5, 6, 3, 7, 4)

scala> val num2 = Set(1, 2 ,3, 6, 8, 5)
num2: scala.collection.mutable.Set[Int] = Set(1, 5, 2, 6, 3, 8)

scala> num1.&(num2)
res105: scala.collection.mutable.Set[Int] = Set(1, 5, 6, 3)

scala> num1.intersect(num2)
res106: scala.collection.mutable.Set[Int] = Set(1, 5, 6, 3)

3.3 Scala Set 常用方法

下面列出了 Scala Set 常用的方法:
(1) def +(elem: A): Set[A]
为集合添加新元素,x并创建一个新的集合,除非元素已存在
(2) def -(elem: A): Set[A]
移除集合中的元素,并创建一个新的集合
(3) def contains(elem: A): Boolean
如果元素在集合中存在,返回 true,否则返回 false。
(4) def &(that: Set[A]): Set[A]
返回两个集合的交集
(5) def &~(that: Set[A]): Set[A]
返回两个集合的差集
(6) def +(elem1: A, elem2: A, elems: A*): Set[A]
通过添加传入指定集合的元素创建一个新的不可变集合
(7) def ++(elems: A): Set[A]
合并两个集合
(8) def -(elem1: A, elem2: A, elems: A*): Set[A]
通过移除传入指定集合的元素创建一个新的不可变集合
(9) def addString(b: StringBuilder): StringBuilder
将不可变集合的所有元素添加到字符串缓冲区
(10) def addString(b: StringBuilder, sep: String): StringBuilder
将不可变集合的所有元素添加到字符串缓冲区,并使用指定的分隔符
(11) def apply(elem: A)
检测集合中是否包含指定元素
(12) def count(p: (A) => Boolean): Int
计算满足指定条件的集合元素个数
(13) def copyToArray(xs: Array[A], start: Int, len: Int): Unit
复制不可变集合元素到数组
(14) def diff(that: Set[A]): Set[A]
比较两个集合的差集
(15) def drop(n: Int): Set[A]]
返回丢弃前n个元素新集合
(16) def dropRight(n: Int): Set[A]
返回丢弃最后n个元素新集合
(17) def dropWhile(p: (A) => Boolean): Set[A]
从左向右丢弃元素,直到条件p不成立
(18) def equals(that: Any): Boolean
equals 方法可用于任意序列。用于比较系列是否相等。
(19) def exists(p: (A) => Boolean): Boolean
判断不可变集合中指定条件的元素是否存在。
(20) def filter(p: (A) => Boolean): Set[A]
输出符合指定条件的所有不可变集合元素。
(21) def find(p: (A) => Boolean): Option[A]
查找不可变集合中满足指定条件的第一个元素
(22) def forall(p: (A) => Boolean): Boolean
查找不可变集合中满足指定条件的所有元素
(23) def foreach(f: (A) => Unit): Unit
将函数应用到不可变集合的所有元素
(24) def head: A
获取不可变集合的第一个元素
(25) def init: Set[A]
返回所有元素,除了最后一个
(26) def intersect(that: Set[A]): Set[A]
计算两个集合的交集
(27) def isEmpty: Boolean
判断集合是否为空
(28) def iterator: Iterator[A]
创建一个新的迭代器来迭代元素
(29) def last: A
返回最后一个元素
(30) def map[B](f: (A) => B): immutable.Set[B]
通过给定的方法将所有元素重新计算
(31) def max: A
查找最大元素
(32) def min: A
查找最小元素
(33) def mkString: String
集合所有元素作为字符串显示
(34) def mkString(sep: String): String
使用分隔符将集合所有元素作为字符串显示
(35) def product: A
返回不可变集合中数字元素的积。
(36) def size: Int
返回不可变集合元素的数量
(37) def splitAt(n: Int): (Set[A], Set[A])
把不可变集合拆分为两个容器,第一个由前 n 个元素组成,第二个由剩下的元素组成
(38) def subsetOf(that: Set[A]): Boolean
如果集合中含有子集返回 true,否则返回false
(39) def sum: A
返回不可变集合中所有数字元素之和
(40) def tail: Set[A]
返回一个不可变集合中除了第一元素之外的其他元素
(41) def take(n: Int): Set[A]
返回前 n 个元素
(42) def takeRight(n: Int):Set[A]
返回后 n 个元素
(43) def toArray: Array[A]
将集合转换为数字
(44) def toBuffer[B >: A]: Buffer[B]
返回缓冲区,包含了不可变集合的所有元素
(45) def toList: List[A]
返回 List,包含了不可变集合的所有元素
(46) def toMap[T, U]: Map[T, U]
返回 Map,包含了不可变集合的所有元素
(47) def toSeq: Seq[A]
返回 Seq,包含了不可变集合的所有元素
(48) def toString(): String
返回一个字符串,以对象来表示

4 Tuple(元组)

与列表一样,元组也是不可变的,但与列表不同的是元组可以包含不同类型的元素。

4.1 元组实例化即获取各元素

元组的值是通过将单个的值包含在圆括号中构成的。例如:

scala> val t = (1, 3.14, "Fred")
t: (Int, Double, String) = (1,3.14,Fred)
//上面定义了一个三元组,类型分别为Int, Double, String,还可以使用Tuple3()来实例化三元组:
scala> val t = new Tuple3(1, 3.14, "Fred")
t: (Int, Double, String) = (1,3.14,Fred)

元组的实际类型取决于它的元素的类型,比如 (99, “runoob”) 是 Tuple2[Int, String]。 (‘u’, ‘r’, “the”, 1, 4, “me”) 为 Tuple6[Char, Char, String, Int, Int, String]。
目前 Scala 支持的元组最大长度为 22。对于更大长度你可以使用集合,或者扩展元组。
访问元组的元素可以通过下划线加数字索引的方式访问,注意元组中的索引从1开始,而不像列表或数组从0开始。
可以使用 t._1 访问第一个元素, t._2 访问第二个元素,如下所示:

scala> val t = new Tuple3(1, 3.14, "Fred")
t: (Int, Double, String) = (1,3.14,Fred)

scala> t._1
res2: Int = 1

scala> t._2
res3: Double = 3.14

scala> t._3
res4: String = Fred

4.2 元组迭代

可以使用 Tuple.productIterator() 方法来迭代输出元组的所有元素

scala> val num = (1, 2 ,5, 6, 8)
num: (Int, Int, Int, Int, Int) = (1,2,5,6,8)

scala> num.productIterator.foreach{ i => println("Value = " + i ) }
Value = 1
Value = 2
Value = 5
Value = 6
Value = 8

4.3 元组转字符串

可以使用 Tuple.toString() 方法将元组的所有元素组合成一个字符串:

scala> val t = new Tuple3("Hello", 66, true)
t: (String, Int, Boolean) = (Hello,66,true)

scala> t.toString
res6: String = (Hello,66,true)

4.4 元素交换

使用 Tuple.swap 方法来交换元组的元素

scala> val t = new Tuple2("www.google.com", "www.baidu.com")
t: (String, String) = (www.google.com,www.baidu.com)

scala> println("交换后的元组: " + t.swap)
交换后的元组:(www.baidu.com,www.google.com)

5 Scala Map(映射)

5.1 Map定义与初始化

Map(映射)是一种可迭代的键值对(key/value)结构。在Map中,所有的值都可以通过键来获取,并且Map 中的键都是唯一的。
Map 也叫哈希表(Hash tables)。Map 有两种类型,可变与不可变,区别在于可变对象可以修改它,而不可变对象不可以。
默认情况下 Scala 使用不可变 Map。如果需要使用可变集合,就需要显式的引入 import scala.collection.mutable.Map 类。
在 Scala中,可以同时使用可变与不可变 Map,不可变的直接使用 Map,可变的使用 mutable.Map(需要引入上面的包)。以下实例演示了不可变 Map 的应用:

scala> var a:Map[Char, Int] = Map()              //定义一个空的映射
a: Map[Char,Int] = Map()

//键值对映射
scala> val colors = Map("red" -> "#FF0000", "azure" -> "#F0FFFF")
colors: scala.collection.immutable.Map[String,String] = Map(red -> #FF0000, azur
e -> #F0FFFF)

scala> val students = Map[String, Int]("zhangsan" -> 23, "lisi" -> 24, "wangwu"
-> 25)
students: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 23, lisi
-> 24, wangwu -> 25)

定义 Map 时,需要为键值对定义类型。如果需要添加 key-value 对,可以使用 + 号,如下所示:

scala> var a:Map[Char, Int] = Map()
a: Map[Char,Int] = Map()
scala> a += ('I' -> 1)
scala> a
res10: Map[Char,Int] = Map(I -> 1)
scala> a += ('J' -> 5)
scala> a += ( 'K' -> 10)
scala> a += ( 'L' -> 100)
scala> a
res14: Map[Char,Int] = Map(I -> 1, J -> 5, K -> 10, L -> 100)

5.2 Map的基本操作

在Scala中,Map有三个基本操作:
Scala学习之——几种常用数据结构(Array、List、Set、Tuple、Map)
注意:上表中的keys和values方法返回的是一个Set类型的集合,其不能通过索引的方式取出Map中的第几个的键和值。
使用上表中的三个方法,对映射进行操作示例:

scala> val students = Map[String, Int]("zhangsan" -> 23, "lisi" -> 24, "wangwu"
-> 25)
students: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 23, lisi
-> 24, wangwu -> 25)

scala> println("students中的键为: " + students.keys)
students中的键为: Set(zhangsan, lisi, wangwu)

scala> println("students中的值为: " + students.values)
students中的值为: MapLike.DefaultValuesIterable(23, 24, 25)

scala> val nums:Map[Int, Int] = Map()
nums: Map[Int,Int] = Map()

scala> nums.isEmpty
res17: Boolean = true

5.3 Map合并

可以使用 ++ 运算符或 Map.++() 方法来连接两个 Map对其进行合并,Map 合并时会移除重复的 key。以下演示了两个 Map 合并的实例:

scala> val students1 = Map[String, Int]("zhangsan" -> 23, "lisi" -> 24, "wangwu"
->
25)
students1: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 23, lisi
->
24, wangwu -> 25)

scala> val students2 = Map[String, Int]("xiaoming" -> 11, "xiaohong" -> 12, "wan
gwu"
-> 33)
students2: scala.collection.immutable.Map[String,Int] = Map(xiaoming -> 11, xiao
hong -> 12, wangwu -> 33)

scala> var students = students1 ++ students2
students: scala.collection.immutable.Map[String,Int] = Map(xiaoming -> 11, lisi
->
24, xiaohong -> 12, wangwu -> 33, zhangsan -> 23) //合并相同的键,并更新其值

scala> students = students1.++(students2)
students: scala.collection.immutable.Map[String,Int] = Map(xiaoming -> 11, lisi
->
24, xiaohong -> 12, wangwu -> 33, zhangsan -> 23)

5.4 Map中对key和value的操作

通过 foreach 循环,可以输出 Map 中的 keys 和 values。另一种获取Map中的键和值的方式,是通过获取所有的key所组成的Set,通过集合的iterator方法返回迭代,这个判断是否还有下一个元素(hasNext方法),之后将通过next方法获取的值放在key中即为关键字,然后通过Map的关键字即可得到其值(即value = Ma(key))。使用 Map.contains 方法,可以查看 Map 中是否存在指定的 Key。
上表中的keys和values方法返回的是一个Set类型的集合,其不能通过索引的方式取出Map中的第几个的键和值。

scala> val sites = Map("google" -> "www.google.com", "baidu" -> "www.baidu.com",
"taobao" -> "www.taobao.com")
sites: scala.collection.immutable.Map[String,String] = Map(google -> www.google.
com, baidu -> www.baidu.com, taobao -> www.taobao.com)

//第一种,获取key和value的方法
scala> sites.keys.foreach{ i => print("Key = " + i); println(", Value = " + site
s(i)) }
Key = google, Value = www.google.com
Key = baidu, Value = www.baidu.com
Key = taobao, Value = www.taobao.com

//第二种,获取key和value的方法
scala> val site = sites.keys.iterator
site: Iterator[String] = non-empty iterator

scala> while(site.hasNext){
var key = site.next
print("Key = " + key);
println(", Value = " + sites(key))
}
Key = google, Value = www.google.com
Key = baidu, Value = www.baidu.com
Key = taobao, Value = www.taobao.com

scala> sites.contains("google")
res24: Boolean = true

scala> sites.contains("amazon")
res25: Boolean = false

5.5 Map中常用的方法

下表列出了 Scala Map 常用的方法:
序号 方法及描述
(1) def ++(xs: Map[(A, B)]): Map[A, B]
返回一个新的 Map,新的 Map xs 组成
(2) def -(elem1: A, elem2: A, elems: A*): Map[A, B]
返回一个新的 Map, 移除 key 为 elem1, elem2 或其他 elems。
(3) def –(xs: GTO[A]): Map[A, B]
返回一个新的 Map, 移除 xs 对象中对应的 key
(4) def get(key: A): Option[B]
返回指定 key 的值
(5) def iterator: Iterator[(A, B)]
创建新的迭代器,并输出 key/value 对
(6) def addString(b: StringBuilder): StringBuilder
将 Map 中的所有元素附加到StringBuilder,可加入分隔符
(7) def addString(b: StringBuilder, sep: String): StringBuilder
将 Map 中的所有元素附加到StringBuilder,可加入分隔符
(8) def apply(key: A): B
返回指定键的值,如果不存在返回 Map 的默认方法
(9) def clear(): Unit
清空 Map
(10) def clone(): Map[A, B]
从一个 Map 复制到另一个 Map
(11) def contains(key: A): Boolean
如果 Map 中存在指定 key,返回 true,否则返回 false。
(12) def copyToArray(xs: Array[(A, B)]): Unit
复制集合到数组
(13) def count(p: ((A, B)) => Boolean): Int
计算满足指定条件的集合元素数量
(14) def default(key: A): B
定义 Map 的默认值,在 key 不存在时返回。
(15) def drop(n: Int): Map[A, B]
返回丢弃前n个元素新集合
(16) def dropRight(n: Int): Map[A, B]
返回丢弃最后n个元素新集合
(17) def dropWhile(p: ((A, B)) => Boolean): Map[A, B]
从左向右丢弃元素,直到条件p不成立
(18) def empty: Map[A, B]
返回相同类型的空 Map
(19) def equals(that: Any): Boolean
如果两个 Map 相等(key/value 均相等),返回true,否则返回false
(20) def exists(p: ((A, B)) => Boolean): Boolean
判断集合中指定条件的元素是否存在
(21) def filter(p: ((A, B))=> Boolean): Map[A, B]
返回满足指定条件的所有集合
(22) def filterKeys(p: (A) => Boolean): Map[A, B]
返回符合指定条件的的不可变 Map
(23) def find(p: ((A, B)) => Boolean): Option[(A, B)]
查找集合中满足指定条件的第一个元素
(24) def foreach(f: ((A, B)) => Unit): Unit
将函数应用到集合的所有元素
(25) def init: Map[A, B]
返回所有元素,除了最后一个
(26) def isEmpty: Boolean
检测 Map 是否为空
(27) def keys: Iterable[A]
返回所有的key/p>
(28) def last: (A, B)
返回最后一个元素
(29) def max: (A, B)
查找最大元素
(30) def min: (A, B)
查找最小元素
(31) def mkString: String
集合所有元素作为字符串显示
(32) def product: (A, B)
返回集合中数字元素的积。
(33) def remove(key: A): Option[B]
移除指定 key
(34) def retain(p: (A, B) => Boolean): Map.this.type
如果符合满足条件的返回 true
(35) def size: Int
返回 Map 元素的个数
(36) def sum: (A, B)
返回集合中所有数字元素之和
(37) def tail: Map[A, B]
返回一个集合中除了第一元素之外的其他元素
(38) def take(n: Int): Map[A, B]
返回前 n 个元素
(39)
def takeRight(n: Int): Map[A, B]
返回后 n 个元素
(40) def takeWhile(p: ((A, B)) => Boolean): Map[A, B]
返回满足指定条件的元素
(41) def toArray: Array[(A, B)]
集合转数组
(42) def toBuffer[B >: A]: Buffer[B]
返回缓冲区,包含了 Map 的所有元素
(43) def toList: List[A]
返回 List,包含了 Map 的所有元素
(44) def toSeq: Seq[A]
返回 Seq,包含了 Map 的所有元素
(45) def toSet: Set[A]
返回 Set,包含了 Map 的所有元素
(46) def toString(): String
返回字符串对象

6 总结

1.从上面的学习中,可以发现:在List、Set、Map中,都有++方法,可以将这些同种类的集合(collection)进行连接合并,返回的类型分别是新的List、Set、Map。所以,对上面的+:/:+/::/:::等方法的使用范围不太清楚时,可以尽量选择使用++方法。
2.在Scala中,存在大量的各式各样的方法,方法中又有各式的操作符、参数类型,有时这些参数之间一个微小符号的差别就可能是变量和函数的区别,如上面参数中的n: Int, b: StringBuilder, key: A等表示的都是变量,变量之后的变量的类型;像p:(A) => Boolean、p: ((A, B)) => Boolean、f: ((A, B)) => Unit等表示的都是函数,冒号之后的圆括号里的是函数的参数列表,右箭头=>之后的类型为未做方法参数尽心传递的函数的返回类型。作为方法的参数的变量参数和函数参数的区别是:函数之后又圆括号,圆括号里面是参数类型;作为参数的函数有返回类型。
例如,在Scala学习之——Option、Iterator中介绍的Iterator中有一个方法,定义为def filter(p: (A) => Boolean): Iterator[A] ,其中的p: (A) => Boolean表达式表示传给filter方法一个参数为A,返回值为Boolean类型的函数p,在方法中可以传入函数名作为参数(可以不带函数的参数列表),如下面迭代器Iterator调用filter方法的实例所示:

//def filter(p: (A) => Boolean): Iterator[A]
//返回一个新迭代器 ,指向迭代器元素中所有满足条件p的元素。

scala> def doubleData(x: Int): Boolean = {
| if(x % 2 == 0) false
| else true
| }
doubleData: (x: Int)Boolean

scala> val iter2 = Iterator(6, 8, 5, 9, 3, 7, 2, 3, 6, 8)
iter2: Iterator[Int] = non-empty iterator

scala> val iter = iter2.filter(doubleData)
iter: Iterator[Int] = non-empty iterator

scala> while(iter.hasNext)
| {
| print(iter.next + ", ")
| }
5, 9, 3, 7, 3,