Scala集合
Scala提供了一套很好的集合實現,提供了一些集合類型的抽象。
Scala 集合分爲可變的和不可變的集合。
可變集合可以在適當的地方被更新或擴展。這意味着你可以修改,添加,移除一個集合的元素。而不可變集合類永遠不會改變。不過,你仍然可以模擬添加,移除或更新操作。但是這些操作將在每一種情況下都返回一個新的集合,同時使原來的集合不發生改變。
集合中基本結構:
![](http://static.javashuo.com/static/loading.gif)
幾種常用集合類型示例:
- // 定義整型 List
- val x = List(1, 2, 3, 4)
-
- // 定義 Set
- var x = Set(1, 3, 5, 7)
-
- // 定義 Map
- val x = Map("one" -> 1, "two" -> 2, "three" -> 3)
-
- // 創建兩個不同類型元素的元組
- val x = (10, "Runoob")
-
- // 定義 Option
- val x: Option[Int] = Some(5)
Scala List(列表)
Scala 列表類似於數組,它們所有元素的類型都相同,但是它們也有所不同:列表是不可變的,值一旦被定義了就不能改變,其次列表 具有遞歸的結構(也就是鏈接表結構)而數組不是。
列表的元素類型 T 可以寫成 List[T]。例如,以下列出了多種類型的列表:
- // 字符串列表
- val site: List[String] = List("Sina", "Google", "Baidu")
-
- // 整型列表
- val nums: List[Int] = List(1, 2, 3, 4)
-
- // 空列表
- val empty: List[Nothing] = List()
-
- // 二維列表
- val dim: List[List[Int]] =
- List(
- List(1, 0, 0),
- List(0, 1, 0),
- List(0, 0, 1)
- )
構造列表的兩個基本單位是 Nil 和 ::
Nil 也可以表示爲一個空列表。
以上實例我們可以寫成如下所示:(::)符號連接順序是從右到左
- // 字符串列表
- val site = "Sina" :: ("Google" :: ("Baidu" :: Nil))
-
- // 整型列表
- val nums = 1 :: (2 :: (3 :: (4 :: Nil)))
-
- // 空列表
- val empty = Nil
-
- // 二維列表
- val dim = (1 :: (0 :: (0 :: Nil))) ::
- (0 :: (1 :: (0 :: Nil))) ::
- (0 :: (0 :: (1 :: Nil))) :: Nil
基本操作
Scala列表有三個基本操作:
- head 返回列表第一個元素
- tail 返回一個列表,包含除了第一元素之外的其他元素:(是一個列表或者Nil)
- isEmpty 在列表爲空時返回true
對於Scala列表的任何操作都可以使用這三個基本操作來表達。代碼示例如下:
- val site = "Sina" :: ("Google" :: ("Baidu" :: Nil))
- val nums = Nil
- //打印測試head、tail、isEmpty功能
- println(site.head)
- println(site.tail)
- println(site.isEmpty)
- println(nums.isEmpty)
打印結果爲:
- Sina
- List(Google, Baidu)
- false
- true
連接列表
你可以使用 ::: 、 List.:::() 或 List.concat() 方法來連接兩個或多個列表。
代碼示例如下:
- val site1 = "Sina" :: ("Google" :: ("Baidu" :: Nil))
- val site2 = "Facebook" :: ("Taobao" :: Nil)
-
- // 使用 ::: 運算符
- var combine = site1 ::: site2
- println( "site1 ::: site2 : " + combine )
-
- // 使用 list.:::() 方法,注意:結果爲site2列表元素在前,site1在後
- combine = site1.:::(site2)
- println( "site1.:::(site2) : " + combine )
-
- // 使用 concat 方法
- combine = List.concat(site1, site2)
- println( "List.concat(site1, site2) : " + combine )
打印結果:
- site1 ::: site2 : List(Sina, Google, Baidu, Facebook, Taobao)
- site1.:::(site2) : List(Facebook, Taobao, Sina, Google, Baidu)
- List.concat(site1, site2) : List(Sina, Google, Baidu, Facebook, Taobao)
List.fill()
我們可以使用 List.fill() 方法來創建一個指定重複數量的元素列表:
- val site = List.fill(3)("Baidu") // 重複 Runoob 3次
- println( "site : " + site )
-
- val num = List.fill(10)(2) // 重複元素 2, 10 次
- println( "num : " + num )
打印結果爲:
- site : List(Baidu, Baidu, Baidu)
- num : List(2, 2, 2, 2, 2, 2, 2, 2, 2, 2)
List.tabulate()
List.tabulate() 方法是通過給定的函數來創建列表。
方法的第一個參數爲元素的數量,可以是二維的,第二個參數爲指定的函數,我們通過指定的函數計算結果並返回值插入到列表中,起始值爲 0,實例如下:
- // 通過給定的函數創建 5 個元素
- val squares = List.tabulate(6)(n => n * n)
- println( "一維 : " + squares )
-
- // 創建二維列表
- val mul = List.tabulate( 4,5 )( _ * _ )
- println( "二維 : " + mul )
打印結果爲:
- 一維 : List(0, 1, 4, 9, 16, 25)
- 二維 : 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))
List.reverse
List.reverse 用於將列表的順序反轉,實例如下:
- val site = "Sina" :: ("Google" :: ("Baidu" :: Nil))
- println( "反轉前 : " + site )
- println( "反轉前 : " + site.reverse )
打印結果爲:
- 反轉前 : List(Sina, Google, Baidu)
- 反轉前 : List(Baidu, Google, Sina)
列表緩存(ListBuffer)
List類能夠提供對列表頭部,而非尾部的快速訪問。如果需要向結尾添加對象,則需要先對錶頭前綴元素方式反向構造列表,完成之後再調用reverse。
上述問題另一種解決方式就是使用ListBuffer,這可以避免reverse操作。ListBuffer是可變對象,它可以更高效的通過添加元素來構建列表。
使用ListBuffer替代List另一個理由是避免棧溢出風險。
ListBuffer使用示例:
- val buf: ListBuffer[Int] = new ListBuffer[Int]
- //往後添加
- buf += 1
- buf += 2
-
- //前綴添加
- val buf2 = 3 +: buf
- println(buf2.toString())
-
- //ListBuffer轉List
- println(buf2.toList.toString())
List常用方法
Scala隊列和棧
隊列
如果你需要先進先出序列,你可以使用Queue(隊列)。Scala集合提供了可變和不可變的Queue。
不可變Queue代碼示例:
- //使用伴生對象創建一個queue
- val que = Queue[Int]()
-
- //使用enqueue爲不可變隊列添加元素
- val que1 = que.enqueue(1)
-
- //往隊列添加多個元素,把集合作爲enqueue的參數
- val que2 = que1.enqueue(List(2,3,4,5))
-
- //從隊列頭部移除元素,使用dequeue
- //第一個參數爲頭部移除的元素,第二個參數爲剩下的隊列
- val (elem1,que3) = que2.dequeue
-
- //打印移除的元素
- println(elem1)
-
- //打印剩下的隊列
- println(que3)
打印結果爲:
可變Queue代碼示例:
- //使用伴生對象創建一個可變queue
- var que = scala.collection.mutable.Queue[String]()
-
- //使用 += 符號添加單個元素
- que += "A"
-
- //使用 ++= 符號添加多個元素
- que ++= List("B","C","D")
-
- //使用dequeue移除頭部元素
- val a = que.dequeue
-
- //打印移除的元素
- println(a)
-
- //打印隊列中剩下的元素
- print(que)
打印結果:
棧
如果需要的是後進先出,你可以使用Stack,它同樣在Scala的集合中有可變和不可變版本。元素的推入使用push,彈出用pop,只獲取棧頂元素而不移除可以使用top。
可變棧示例:
- //使用Stack類的伴生對象創建Stack對象
- var stack = scala.collection.mutable.Stack[Int]()
-
- //往棧stack中壓如元素
- stack.push(1)
- stack.push(2)
- stack.push(3)
-
- //打印查看棧內元素
- println(stack)
-
- //獲取棧頂元素的值
- val tval = stack.top
- println("棧頂元素爲 : " + tval)
-
- //移除棧頂元素
- val pval = stack.pop()
- println("移除的棧頂元素爲 : " + pval)
-
- //打印移除棧頂元素後,剩下的棧內元素
- println(stack)
打印結果:
- Stack(3, 2, 1)
- 棧頂元素爲 : 3
- 移除的棧頂元素爲 : 3
- Stack(2, 1)
隊列和棧常用操作
Scala Set(集)
- Scala Set(集)是沒有重複的對象集合,所有的元素都是唯一的。
- Scala 集合分爲可變的和不可變的集合。
- 默認情況下,Scala 使用的是不可變集合,如果想使用可變集合,需引用 scala.collection.mutable.Set 包。
- 默認引用 scala.collection.immutable.Set。
不可變集合實例如下:
- val set = Set(1,2,3)
- println(set.getClass.getName) //
-
- println(set.exists(_ % 2 == 0)) //true
- println(set.drop(1)) //Set(2,3)
打印結果爲:
- scala.collection.immutable.Set$Set3
- true
- Set(2, 3)
如果需要使用可變集合需要引入 scala.collection.mutable.Set:
- import scala.collection.mutable.Set // 可以在任何地方引入 可變集合
-
- val mutableSet = Set(1,2,3)
- println(mutableSet.getClass.getName) // scala.collection.mutable.HashSet
- //往集合內添加元素4
- mutableSet.add(4)
- //刪除值爲1的元素
- mutableSet.remove(1)
- //添加元素5
- mutableSet += 5
- //刪除值爲3的元素
- mutableSet -= 3
-
- println(mutableSet) // Set(5, 3, 4)
-
- val another = mutableSet.toSet
- println(another.getClass.getName) // scala.collection.immutable.Set
注意: 雖然可變Set和不可變Set都有添加或刪除元素的操作,但是有一個非常大的差別。對不可變Set進行操作,會產生一個新的set,原來的set並沒有改變,這與List一樣。 而對可變Set進行操作,改變的是該Set本身,與ListBuffer類似。
Set集合基本操作
Scala Set集合有三個基本操作:
- head 返回集合第一個元素
- tail 返回一個集合,包含除了第一元素之外的其他元素
- isEmpty 在集合爲空時返回true
對於Scala集合的任何操作都可以使用這三個基本操作來表達。
代碼示例如下:
- val site = Set("Sina", "Google", "Baidu")
- val nums: Set[Int] = Set()
-
- println( "head : " + site.head )
- println( "tail : " + site.tail )
- println( "isEmpty : " + site.isEmpty )
- println( "isEmpty : " + nums.isEmpty )
打印結果爲:
- head : Sina
- tail : Set(Google, Baidu)
- isEmpty : false
- isEmpty : true
連接集合
你可以使用 ++ 運算符或 Set.++() 方法來連接兩個集合。如果元素有重複的就會移除重複的元素。實例如下:
- val site1 = Set("Sina", "Google", "Baidu")
- val site2 = Set("Faceboook", "Taobao")
-
- // ++ 作爲運算符使用
- var site = site1 ++ site2
- println( "site1 ++ site2 : " + site )
-
- // ++ 作爲方法使用
- site = site1.++(site2)
- println( "site1.++(site2) : " + site )
打印結果爲:
- site1 ++ site2 : Set(Faceboook, Taobao, Sina, Google, Baidu)
- site1.++(site2) : Set(Faceboook, Taobao, Sina, Google, Baidu)
查找集合中最大與最小元素
你可以使用 Set.min 方法來查找集合中的最小元素,使用 Set.max 方法查找集合中的最大元素。實例如下:
- val num = Set(5,6,9,20,30,45)
-
- // 查找集合中最大與最小元素
- println( "Set(5,6,9,20,30,45) 最小元素是 : " + num.min )
- println( "Set(5,6,9,20,30,45) 最大元素是 : " + num.max )
打印結果爲:
- Set(5,6,9,20,30,45) 最小元素是 : 5
- Set(5,6,9,20,30,45) 最大元素是 : 45
交集
你可以使用 Set.& 方法或 Set.intersect 方法來查看兩個集合的交集元素。實例如下:
- val num1 = Set(5,6,9,20,30,45)
- val num2 = Set(50,60,9,20,35,55)
-
- // 交集
- println( "num1.&(num2) : " + num1.&(num2) )
- println( "num1.intersect(num2) : " + num1.intersect(num2) )
打印結果爲:
- num1.&(num2) : Set(20, 9)
- num1.intersect(num2) : Set(20, 9)
Scala Set 常用方法
Scala Map(映射)
- Map(映射)是一種可迭代的鍵值對(key/value)結構。
- 所有的值都可以通過鍵來獲取。
- Map 中的鍵都是唯一的。
- Map 也叫哈希表(Hash tables)。
- Map 有兩種類型,可變與不可變,區別在於可變對象可以修改它,而不可變對象不可以。
- 默認情況下 Scala 使用不可變 Map。如果你需要使用可變集合,你需要顯式的引入 import scala.collection.mutable.Map 類
- 在 Scala 中 你可以同時使用可變與不可變 Map,不可變的直接使用 Map,可變的使用 mutable.Map。
以下實例演示了不可變 Map 的應用:
- // 空哈希表,鍵爲字符串,值爲整型
- var A:Map[Char,Int] = Map()
-
- // Map 鍵值對演示
- val lang= Map("Java" -> "Oracle", "C#" -> "Microsoft")
- 或者
- val lang= Map(("Java","Oracle"), ("C#" , "Microsoft"))
定義 Map 時,需要爲鍵值對定義類型。如果需要添加 key-value 對,可以使用 + 號,如下所示:
Map 基本操作
Scala Map 幾種基本操作:keys、values、isEmpty、賦值(可變映射)
代碼示例:
Keys:
- val lang = Map("Java" -> "Oracle",
- "C#" -> "Microsoft",
- "Swift" -> "Apple")
- Values:
- val nums: Map[Int, Int] = Map()
- println( "lang 中的鍵爲 : " + lang.keys )
- println( "lang 中的值爲 : " + lang.values )
isEmpty:
- println( "lang 是否爲空 : " + lang.isEmpty )
- println( "nums 是否爲空 : " + nums.isEmpty )
keys和isEmpty的打印結果爲:
- lang 中的鍵爲 : Set(Java, C#, Swift)
- lang 中的值爲 : MapLike(Oracle, Microsoft, Apple)
- lang 是否爲空 : false
- nums 是否爲空 : true
賦值:
- var lang= scala.collection.mutable.Map("Java" -> "Oracle", "C#" -> "Microsoft")
- lang("Java") = "sun"
- println(lang)
打印結果爲:
- Map(C# -> Microsoft, Java -> sun)
Map 合併
你可以使用 ++ 運算符或 Map.++() 方法來連接兩個 Map,Map 合併時會移除重複的 key。以下演示了兩個 Map 合併的實例:
- val lang =Map("Java" -> "Oracle",
- "C#" -> "Microsoft",
- "Swift" -> "Apple")
- val color = Map("blue" -> "#0033FF",
- "yellow" -> "#FFFF00",
- "red" -> "#FF0000")
-
- // ++ 作爲運算符
- var colors = lang ++ color
- println( "lang ++ colors : " + colors )
-
- // ++ 作爲方法
- colors = lang.++(colors)
- println( "lang.++(colors)) : " + colors )
打印結果爲:
- lang ++ colors : Map(blue -> #0033FF, C# -> Microsoft, yellow -> #FFFF00, Java -> Oracle, red -> #FF0000, Swift -> Apple)
- )
-
- // ++ 作爲運算符
- var colors = lang ++ color
- println( "lang ++ colors : " + colors )
-
- // ++ 作爲方法
- colors = lang.++(colors)
- println( "lang.++(colors)) : " + colors )
打印結果爲:
- lang ++ colors : Map(blue -> #0033FF, C# -> Microsoft, yellow -> #FFFF00, Java -> Oracle, red -> #FF0000, Swift -> Apple)
- lang.++(colors)) : Map(blue -> #0033FF, C# -> Microsoft, yellow -> #FFFF00, Java -> Oracle, red -> #FF0000, Swift -> Apple)
輸出 Map 的 keys 和 values
以下通過 foreach 循環輸出 Map 中的 keys 和 values:
- val lang =Map("Java" -> "Oracle",
- "C#" -> "Microsoft",
- "Swift" -> "Apple")
-
- lang.keys.foreach{ i =>
- print( "Key = " + i )
- println("\tValue = " + lang(i) )}
打印結果爲:
- Key = JavaValue = Oracle
- Key = C#Value = Microsoft
- println("\tValue = " + lang(i) )}
打印結果爲:<