Scala的集合類可以從三個維度進行切分:
可變與不可變集合(Immutable and mutable collections)
靜態與延遲加載集合 (Eager and delayed evaluation )
串行與并行計算集合(Sequential and parallel evaluation )
transformation,集合中有大量的操作都是把一個集合“轉換”成另一個集合,比如map,filter等等。而Eager和Delayed集合的區別在于:Eager集合總是立即為元素分配內存,當遇到一個transform動作時,Eager的集合會直接計算并返回結果,而Delayed集合則會盡可能晚的推遲執行,直到必須返回結果時才去執行。這一點和Spark RDD操作中的transformation和action非常類似。
在現有的集合里,只有Stream是Lasy的,所有其他的集合都是靜態(Eager)加載的。但是你可以很容易地把一個靜態集合轉換成lazy的,那就是創建一個view。
集合類型總覽
Immutable?Collection
Immutable Seq
Seq主要分兩大類:indexed sequences和linear sequences,indexed sequences暗示本類集合在隨機讀取方面有較高的性能(類似數據結構中的數組)。linear sequences暗示本類集合在head和tail操作和順序遍歷上更有優勢(類似于數據結構中的雙向列表)
在使用Seq時,默認使用的具體類是List, 使用IndexedSeq時默認使用的具體類是Vector.
scala> val seq = Seq(1,2,3)seq: Seq[Int]= List(1,2,3)scala> val indexedSeq = IndexedSeq(1,2,3)indexedSeq: IndexedSeq[Int]= Vector(1,2,3)
Immutable Set
Immutable Map
Mutable Seq
如何選擇集合類
各種Immutable Sequence的特性比較
各種Mutable Sequence的特性比較
各種Map的特性比較
各種Set的特性比較
一、常用操作符(操作符其實也是函數)
++ ++[B](that: GenTraversableOnce[B]): List[B] 從列表的尾部添加另外一個列表
++: ++:[B >: A, That](that: collection.Traversable[B])(implicit bf: CanBuildFrom[List[A], B, That]): That 在列表的頭部添加一個列表
+: +:(elem: A): List[A] 在列表的頭部添加一個元素
:+ :+(elem: A): List[A] 在列表的尾部添加一個元素
:: ::(x: A): List[A] 在列表的頭部添加一個元素
::: :::(prefix: List[A]): List[A] 在列表的頭部添加另外一個列表
:\ :[B](z: B)(op: (A, B) ?6?0 B): B 與foldRight等價
val left = List(1,2,3)
val right = List(4,5,6)
//以下操作等價
left ++ right? // List(1,2,3,4,5,6)
left ++: right? // List(1,2,3,4,5,6)
right.++:(left)? ? // List(1,2,3,4,5,6)
right.:::(left)? // List(1,2,3,4,5,6)
//以下操作等價
0 +: left? ? //List(0,1,2,3)
left.+:(0)? //List(0,1,2,3)
//以下操作等價
left :+ 4? ? //List(1,2,3,4)
left.:+(4)? //List(1,2,3,4)
//以下操作等價
0 :: left? ? ? //List(0,1,2,3)
left.::(0)? ? //List(0,1,2,3)
任何以冒號結果的操作符,都是右綁定的,即 0 :: List(1,2,3) = List(1,2,3).::(0) = List(0,1,2,3) 從這里可以看出操作::其實是右邊List的操作符,而非左邊Int類型的操作符
5.util包
http://www.scala-lang.org/docu/files/collections-api/collections.html
The following figure shows all collections in packagescala.collection. These are all high-level abstract classes or traits, which generally have mutable as well as immutable implementations.
Sequences, classes that inherit from traitSeq,let you work with groups of data lined up in order. Because the elements are ordered, you can ask for the first element, second element, 103rd element, and so on.
scala.collection.immutable
The immutability helps you develop correct, efficient algorithms because you never need to make copies of acollection.
scala.collection.mutable
不可變(collection.immutable._)
可變(collection.mutable._)
Array
ArrayBuffer
List
ListBuffer
String
StringBuilder
/
LinkedList, DoubleLinkedList
List
MutableList
/
Queue
Array
ArraySeq
Stack
Stack
HashMap HashSet
HashMap HashSet
ArrayStack
Array
長度固定
元素可變
確定長度,后賦值;
List
長度固定
元素不可變
Tuple
長度固定
元素不可變
常用于有多個返回值的函數;或者多個變量的同時定義
Scala2.8中,3者的元素都可以混合不同的類型(轉化為Any類型);
Scala2.7中,Array、List都不能混合類型,只有Tuple可以;
Arraysallow you to hold a sequence of elements and efficiently access an element at an arbitrary position,both to get or update the element, with a zero-based index.
Listssupport fast addition and removal of items to the beginning of the list, but theydo notprovidefast accessto arbitrary indexes because theimplementation must iterate through the list linearly.
5.2.1.1Array
val list1 = new Array[String](0) // Array()
val list2 = new Array[String](3) // Array(null, null, null)
val list3:Array[String] = new Array(3) // // Array(null, null, null)
val list1 = Array("a","b","c","d") //相當于Array.apply("a","b","c","d")
定義一個類型為Any的Array:
val aa = Array[Any](1, 2)
或:
val aa: Array[Any] = Array(1, 2)
或:
val aa: Array[_] = Array(1, 2)
定義:
Array (1,3,5,7,9,11)
也可以用
Array[Int](1 to 11 by 2:_*)
暫時還沒有找到Range(例如 1 to 11 by 2)之后跟:_*的依據
Array對應的可變ArrayBuffer:
val ab =collection.mutable.ArrayBuffer[Int]()
ab += (1,3,5,7)
ab ++= List(9,11) // ArrayBuffer(1, 3, 5, 7, 9, 11)
ab toArray // Array (1, 3, 5, 7, 9, 11)
ab clear // ArrayBuffer()
5.2.1.2List
val list:List[Int]= List(1,3,4,5,6) //或者List(1 to 6:_*)
val list1 = List("a","b","c","d") //或者List('a' to 'd':_*) map (_.toString)
元素合并進List用::
val list2 = "a"::"b"::"c"::Nil // Nil是必須的
val list3 = "begin" :: list2 // list2不變,只能加在頭,不能加在尾
多個List合并用++,也可以用:::(不如++)
val list4 = list2++"end"++Nil
val list4 = list2:::"end" :: Nil //相當于list2 ::: List("end")
當import java.util._之后會產生沖突,需要指明包
scala.List(1,2,3)
List對應的可變ListBuffer:
val lb =scala.collection.mutable.ListBuffer(1,2,3)
lb.append(4) // ListBuffer(1, 2, 3, 4)
val lb =collection.mutable.ListBuffer[Int]()
lb += (1,3,5,7)
lb ++= List(9,11) // ListBuffer(1, 3, 5, 7, 9, 11)
lb.toList // List(1, 3, 5, 7, 9, 11)
lb.clear // ListBuffer()
建議定義方式:
val head::body = List(4,"a","b","c","d")
// head: Any = 4
// body: List[Any] = List(a, b, c, d)
val a::b::c = List(1,2,3)
// a: Int = 1
// b: Int = 2
// c: List[Int] = List(3)
定義固定長度的List:
List.fill(10)(2)// List(2, 2, 2, 2, 2, 2, 2, 2, 2, 2)
Array.fill(10)(2)// Array(2, 2, 2, 2, 2, 2, 2, 2, 2, 2)
又如:
List.fill(10)(scala.util.Random.nextPrintableChar)
// List(?, =, ^, L, p, <, \, 4, 0, !)
List.fill(10)(scala.util.Random.nextInt(101))
// List(80, 45, 26, 75, 24, 72, 96, 88, 86, 15)
5.2.1.3Tuple
val t1 = ("a","b","c")
var t2 = ("a", 123, 3.14, new Date())
val (a,b,c) = (2,4,6)
最簡單的Tuple:
1->"hello world"
和下面的寫法是等價的:
(1, "hello world")
To access elements of a tuple, you can use method_1to access the first element,_2to access the second, and so on:
scala> val v = (1, "Nick", 43)
scala> v._1
res179: Int = 1
scala> v._2
res180: String = Nick
scala> v._3
res181: Int = 43
5.2.1.4Vector
Scala2.8為了提高list的隨機存取效率而引入的新集合類型(而list存取前部的元素快,越往后越慢)。
val v = Vector.empty
val v2 = 0+:v:+10:+20 // Vector(0, 10, 20), Vector那一邊始終有":"
v2(1) // 10
v2updated(1,100) // Vector(0, 100, 20)
這個例子舉的不太好,scala.collection.immutable. Vector擴展、updated之后是新生成的vector,原vector保持immutable。這點和List類似。
Seq的缺省實現是List:
Seq(1,2,3) // List(1, 2, 3)
IndexSeq的缺省實現是Vector:
IndexSeq(1,2,3) // Vector(1, 2, 3)
5.2.1.5Range
Range(0, 5) // (0,1,2,3,4)
等同于:
0 until 5
等同于:
0 to 4
兩個Range相加:
('0' to '9') ++ ('A' to 'Z') // (0,1,..,9,A,B,...,Z)
Range和序列轉換:
1 to 5 toList
相當與:
List(1 to 5:_*)
或者:
Vector(1 to 5: _*) // Vector(1,2,3,4,5)
5.2.1.6Stack Queue (List類的sibling)
先進后出的堆棧:
val s =collection.immutable.Stack()
You push an element onto a stack withpush, pop an element withpop, and peek at the top of the stack without removing it withtop/head.
val s2 = s.push(10,20,30) // Stack(30, 20, 10)
s2.head// 30
s2.pop.pop // Stack(10)
對應的可變Stack:
val ms =collection.mutable.Stack()
ms.push(1,3,5).push(7) // Stack(7, 5, 3, 1)
ms.head // 7
ms.pop // 7, ms = Stack(5,3,1)
先進先出的隊列:
val q =collection.immutable.Queue() //也可指定類型Queue[Int]()
//You can append an element to an immutable queue withenqueue:
val q2 = q.enqueue(0).enqueue(List(10,20,30)) // Queue(0, 10, 20, 30)
//To remove an element from the head of the queue, you usedequeue:
q2.dequeue._1 // 0
q2.dequeue._2 // Queue(10, 20, 30)
On immutable queues, thedequeuemethod returns a pair (aTuple2) consisting of the element at the head of the queue, and the rest of the queue with the head element removed.
val qHas123 = Queue(1,2,3)
scala>val(element,?has23)?=?qHas123.dequeueelement:?Int?=?1has23:scala.collection.immutable.Queue[Int]?=?Queue(2,3)
對應的可變Queue:
You use a mutable queue similarly to how you use an immutable one, but instead ofenqueue, you use the+=and++=operators to append. Also, on a mutable queue, thedequeuemethod will just remove the head element from the queue and return it.
val mq =collection.mutable.Queue[Int]()
mq+=(1,3,5)
mq++=List(7,9) // Queue(1, 3, 5, 7, 9)
mq dequeue // 1, mq= Queue(3, 5, 7, 9)
mq clear // Queue()
If you need a first-in-first-out sequence, you can use aQueue.
If you need a last-in-first-out sequence, you can use aStack.
5.2.1.7Stream
Stream相當于lazy List,避免在中間過程中生成不必要的集合。
定義生成:
val st = 1#::2#::3#::Stream.empty // Stream(1, ?)
例子:fib數列的Stream版本簡單易懂
def fib(a: Int, b: Int): Stream[Int] = a#::fib(b,? a+b)
valfibs = fib(1, 1).take(7).toList // List(1, 1, 2, 3, 5, 8, 13)
fib數列的前后項比值趨于黃金分割:
def fn(n:Int) = fib(1,1)(n)
1 to 10 map (n=> 1.0*fn(n)/fn(n+1)) // Vector(0.5, 0.666, ..., 0.618)
例子1:
Range(1,50000000).filter (_ % 13==0)(1) // 26,但很慢,需要大量內存
Stream.range(1,50000000).filter(_%13==0)(1) // 26,很快,只計算最終結果需要的內容
注意:
第一個版本在filter后生成一個中間collection,size=50000000/13;而后者不生成此中間collection,只計算到26即可。
例子2:
(1 to 100).map(i=> i*3+7).filter(i=> (i%10)==0).sum // map和filter生成兩個中間collection
(1 to 100).toStream.map(i=> i*3+7).filter(i=> (i%10)==0).sum
5.2.2.使用(map, flatMap, filter, exists等)
5.2.2.1map
//類型可以混合:
import java.util._
val list3 = Array("a", 123, 3.14, new Date())
List("a","b","c").map(s=>s.toUpperCase()) //方式1
List("a","b","c").map(_.toUpperCase()) ????//方式2,類似于Groovy的it
// = List(A, B, C)
5.2.2.2filter filterNot
List(1,2,3,4,5).filter(_%2==0) // List(2, 4)
也可以寫成:
for (x<-List(1,2,3,4,5) if x%2==0) yield x
List(1,2,3,4,5).filterNot(_%2==0) // List(1, 3, 5)
5.2.2.3partition span splitAt groupBy
注:val (a,b) = List(1,2,3,4,5).partition(_%2==0) // (List(2,4), List(1,3,5))
可把Collection分成:滿足條件的一組,其他的另一組。
和partition相似的是span,但有不同:
List(1,9,2,4,5).span(_<3)// (List(1),List(9, 2, 4, 5)),碰到不符合就結束
List(1,9,2,4,5).partition(_<3)// (List(1, 2),List(9, 4, 5)),掃描所有
List(1,3,5,7,9)splitAt2// (List(1, 3),List(5, 7, 9))
List(1,3,5,7,9)groupBy(5<)// Map((true,List(7, 9)), (false,List(1, 3, 5)))
5.2.2.4foreach
打印:
Array("a","b","c","d").foreach(printf("[%s].",_))
// [a].[b].[c].[d].
5.2.2.5exists
//集合中是否存在符合條件的元素
List(1,2,3,4,5).exists(_%3==0) // true
5.2.2.6find
返回序列中符合條件的第一個。
例子:查找整數的第一個因子(最小因子、質數)
def fac1(n:Int) = if (n>= -1 && n<=1) n else (2 to n.abs) find (n%_==0) get
5.2.2.7sorted sortWith sortBy
例子(排序):
List(1,3,2,0,5,9,7).sorted//List(0, 1, 2, 3, 5, 7, 9)
List(1,3,2,0,5,9,7).sortWith(_>_)// List(9, 7, 5, 3, 2, 1, 0)
List("abc", "cb", "defe", "z").sortBy(_.size) //List(z, cb, abc, defe)
List((1,'c'), (1,'b'), (2,'a')).sortBy(_._2)// List((2,a), (1,b), (1,c))
5.2.2.8distinct
例子:(去除List中的重復元素)
def uniq[T](l:List[T]) = l.distinct
uniq(List(1,2,3,2,1)) // List(1,2,3)
5.2.2.9flatMap
flatMap的作用:把多層次的數據結構“平面化”,并去除空元素(如None)。
可用于:得到xml等樹形結構的所有節點名稱,去除None等
List(1,2,3) * List(10,20,30) = List(10, 20, 30,20, 40, 60,30, 60, 90)
val (a,b) = (List(1,2,3), List(10,20,30))
aflatMap(i=> b map (j=> i*j))
等同于:
for (i<-a; i<-b) yield i*j //這個寫法更清晰
例子1b:
如果不用flatMap而是用map,結果就是:
amap(i=> b map (j=> i*j))// List(List(10, 20, 30), List(20, 40, 60), List(30, 60, 90))
等同于:
for (i<-a) yield { for (j<-b) yield i*j } //不如上面的清晰
例子2:
List("abc","def") flatMap (_.toList) // List(a, b, c, d, e, f)
而
List("abc","def") map (_.toList) // List(List(a, b, c), List(d, e, f))
例子3:flatMap結合Option
def toint(s:String) =
try { Some(Integer.parseInt(s)) } catch { case e:Exception => None }
List("123", "12a", "45") flatMap toint // List(123, 45)
List("123", "12a", "45") map toint // List(Some(123), None, Some(45))
5.2.2.10indices,zipWithIndex, slice
得到indices:
val a = List(100,200,300)
aindices// (0,1,2)
azipWithIndex// ((100,0), (200,1), (300,2))
(a indices) zip a // ((0,100), (1,200), (2,300))
截取一部分,相當于String的substring
List(100,200,300,400,500)slice(2,4) // (300,400),取l(2), l(3)
5.2.2.11take drop splitAt
List(1,3,5,7) take 2 // List(1,3)
List(1,3,5,7) drop 2 // List(5,7)
5.2.2.12count
滿足條件的元素數目:
例如1000內質數的個數:
def prime(n:Int) = if (n<2) false else 2 to math.sqrt(n).toInt forall (n%_!=0)
1 to 1000countprime? // 168
5.2.2.13updated patch
對于immutable的數據結構,使用updated返回一個新的copy:
val v1 = List(1,2,3,4)
v1.updated(3,10) // List(1, 2, 3,10), v1還是List(1, 2, 3,4)
對于可變的數據結構,直接更改:
val mseq =scala.collection.mutable.ArraySeq(1, 2, 4,6)
mseq(3) = 10 // mseq = ArraySeq(1, 2, 4,10)
批量替換,返回新的copy:
val v1 = List(1,2,3,4,5)
val v2 = List(10,20,30)
v1 patch (0, v2, 3) // List(10,20,30,4,5),但v1,v2不變
5.2.2.14reverse reverseMap
1 to 5reverse// Range(5, 4, 3, 2, 1)
"james".reverse.reverse // "james"
reverseMap就是revese + map
1 to 5reverseMap(10*) // Vector(50, 40, 30, 20, 10)
相當于:
(1 to 5 reverse) map (10*)
5.2.2.15contains startsWith endWith
1 to 5contains3 // true,后一個參數是1個元素
1 to 5containsSlice(2 to 4) // true,后一個參數是1個集合
(1 to 5)startsWith(1 to 3) // true后一個參數是1個集合
(1 to 5)endsWith(4 to 5)
(List(1,2,3)correspondsList(4,5,6)) (_<_)// true,長度相同且每個對應項符合判斷條件
5.2.2.16集合運算
List(1,2,3,4)intersectList(4,3,6) //交集= List(3, 4)
List(1,2,3,4)diffList(4,3,6) // A-B = List(1, 2)
List(1,2,3,4)unionList(4,3,6) // A+B = List(1, 2, 3, 4, 4, 3, 6)
//相當于
List(1,2,3,4)++List(4,3,6) // A+B = List(1, 2, 3, 4, 4, 3, 6)
5.2.2.17殊途同歸
例子:得到(4, 16, 36, 64, 100)
寫法1:
(1 to 10)filter(_%2==0)map(x=>x*x)
寫法2:
for(x<-1 to 10ifx%2==0)yieldx*x
寫法3:
(1 to 10)collect{casexifx%2==0 => x*x }
5.2.2.18其他
對其他語言去重感興趣,可看看:
http://rosettacode.org/wiki/Remove_duplicate_elements
統一使用(),而不是[],()就是apply()的簡寫,a(i)===a.apply(i)
// Array
val a = Array(100,200,300) // a(0)=100, a(1)=200, a(3)=300
a(0) // 100,相當于a.apply(0)
a(0)=10 // Array(10, 200, 300),相當于a.update(0, 10)
// List
val list = List("a","b","c")
// list(0)=="a", list(1)=="b", list(2)=="c"
由于List不是index sequence,定位訪問成本高,不建議使用。同樣不建議使用的還有List 的 length
// Tuple
val t1 = ("a","b","c") // t1._1="a", t1._2="b", t1._3="c"
在某類型的集合對象上調用view方法,得到相同類型的集合,但所有的transform函數都是lazy的,從該view返回調用force方法。
對比:
val v = Vector(1 to 10:_*)
v map (1+) map (2*) //Vector(4,?6,?8,?10,?12,?14,?16,?18,?20,?22)
以上過程得生成2個新的Vector,而:
val v = Vector(1 to 10:_*)
v.view map (1+) map (2*) force
只在過程中生成1個新的Vector,相當于:
v map (x=>2*(1+x))
又如:
((1 to 1000000000) view).take(3).force // Vector(1,2,3)
使用Stream:
Stream.range(1,1000000000).take(3).force // ?Stream(1, 2, 3)
方案一:Java的List很容易通過List.toArray轉換到Array,和Scala中的Array是等價的,可使用map、filter等。
方案二:使用第三方的scalaj擴展包(需自行下載設置classpath)
例子1:
val a1 = new java.util.ArrayList[Int]
a1.add(100); a1.add(200); a1.add(300)
val a2 = a1.toArray
a2 map (e=>e.asInstanceOf[Int]) map(2*) filter (300>)
//采用scalaj(http://github.com/scalaj/scalaj-collection)
import scalaj.collection.Imports._
val a3 = a1.asScala
//scala->java
List(1, 2, 3).asJava
Map(1 -> "a", 2 -> "b", 3 -> "c").asJava
Set(1, 2, 3).asJava
// scalaj還可以在java的collection上使用foreach (目前除foreach外,還不支持filter、map)
a1.foreach(println)
scalaj的簡易文檔如下:
Java類型
轉換方法
java.lang.Comparable[A]
#asScala:scala.math.Ordered[A]
java.util.Comparator[A]
#asScala:scala.math.Ordering[A]
java.util.Enumeration[A]
#asScala:scala.collection.Iterator[A]
#foreach(A => Unit): Unit
java.util.Iterator[A]
#asScala:scala.collection.Iterator[A]
#foreach(A => Unit): Unit
java.lang.Iterable[A]
#asScala:scala.collection.Iterable[A]
#foreach(A => Unit): Unit
java.util.List[A]
#asScala:scala.collection.Seq[A]
#asScalaMutable:scala.collection.mutable.Seq[A]
java.util.Set[A]
#asScala:scala.collection.Set[A]
#asScalaMutable:scala.collection.mutable.Set[A]
java.util.Map[A, B]
#asScala:scala.collection.Map[A, B]
#asScalaMutable:scala.collection.mutable.Map[A, B]
#foreach(((A, B)) => Unit): Unit
java.util.Dictionary[A, B]
#asScala:scala.collection.mutable.Map[A, B]
#foreach(((A, B)) => Unit): Unit
//Scalato Java
Scala類型
轉換方法
scala.math.Ordered[A]
#asJava: java.util.Comparable[A]
scala.math.Ordering[A]
#asJava: java.util.Comparator[A]
scala.collection.Iterator[A]
#asJava: java.util.Iterator[A]
#asJavaEnumeration: java.util.Enumeration[A]
scala.collection.Iterable[A]
#asJava: java.lang.Iterable[A]
scala.collection.Seq[A]
#asJava: java.util.List[A]
scala.collection.mutable.Seq[A]
#asJava: java.util.List[A]
scala.collection.mutable.Buffer[A]
#asJava: java.util.List[A]
scala.collection.Set[A]
#asJava: java.util.Set[A]
scala.collection.mutable.Set[A]
#asJava: java.util.Set[A]
scala.collection.Map[A, B]
#asJava: java.util.Map[A, B]
scala.collection.mutable.Map[A, B]
#asJava: java.util.Map[A, B]
#asJavaDictionary: java.util.Dictionary[A, B]
var m = Map[Int, Int]()
var m = Map(1->100, 2->200)
或者
var m = Map((1,100), (2,200))
相加:
val m = Map(1->100, 2->200)++Map(3->300)//Map((1,100), (2,200), (3,300))
可以用zip()生成Map:
List(1,2,3).zip(List(100,200,300)).toMap// Map((1,100), (2,200), (3,300))
注解:zip有“拉拉鏈”的意思,就是把兩排鏈扣完全對應扣合在一起,非常形象。
l定義:
val m2 =Map()
val m3 =Map(1->100, 2->200, 3->300)
指定類型:
val m1:Map[Int,String]= Map(1->"a",2->"b")
注:如果import java.util._后發生沖突,可指明:scala.collection.immutable.Map
保持循序的Map可以使用:
collection.immutable.ListMap
l讀取元素:
// m3(1)=100, m3(2)=200, m3(3)=300
// m3.get(1)=Some(100), m3.get(3)=Some(300), m3.get(4)=None
val v = m3.get(4).getOrElse(-1) // -1
或者簡化成:
m3.getOrElse(4, -1) // -1
l增加、刪除、更新:
Map本身不可改變,即使定義為var,update也是返回一個新的不可變Map:
var m4 = Map(1->100)
m4 += (2->200) // m4指向新的(1->100,2->200), (1->100)應該被回收
另一種更新方式:
m4.updated(1,1000)
增加多個元素:
Map(1->100,2->200)+(3->300, 4->400) // Map((1,100), (2,200), (3,300), (4,400))
刪除元素:
Map(1->100,2->200,3->300)-(2,3) // Map((1,100))
Map(1->100,2->200,3->300)--List(2,3) // Map((1,100))
l合并Mpa:
Map(1->100,2->200)++Map(3->300) // Map((1,100), (2,200), (3,300))
val map =scala.collection.mutable.Map[String, Any]()
map("k1")=100???? //增加元素,方法1
map += "k2"->"v2" //增加元素,方法2
// map("k2")=="v2", map.get("k2")==Some("v2"), map.get("k3")==None
有則取之,無則加之:
val mm =collection.mutable.Map(1->100,2->200,3->300)
mmgetOrElseUpdate(3,-1) // 300, mm不變
mmgetOrElseUpdate(4,-1) // 300, mm=Map((2,200),(4,-1), (1,100), (3,300))
刪除:
val mm =collection.mutable.Map(1->100,2->200,3->300)
mm-=1 // Map((2,200), (3,300))
mm-=(2,3) // Map()
mm+=(1->100,2->200,3->300) // Map((2,200), (1,100), (3,300))
mm--=List(1,2) // Map((3,300))
mmremove1 // Some(300), mm=Map()
mm+=(1->100,2->200,3->300)
mm.retain((x,y) => x>1) // mm = Map((2,200), (3,300))
mm.clearn// mm = Map()
改變value:
mmtransform((x,y)=> 0) // mm = Map((2,0), (1,0), (3,0))
mm transform ((x,y)=> x*10) // Map((2,20), (1,10), (3,30))
mm transform ((x,y)=> y+3) // Map((2,23), (1,13), (3,33))
使用Java的HashMap:
val m1:java.util.Map[Int, String] = new java.util.HashMap
上面說過,Map(1->100,2->200,3->300)和Map((1,100),(2,200),(3,300))的寫法是一樣的,可見Map中的每一個entry都是一個Tuple,所以:
for(e<-map) println(e._1 + ": " + e._2)
或者
map.foreach(e=>println(e._1 + ": " + e._2))
或者(最好)
for ((k,v)<-map) println(k + ": " + v)
也可以進行filter、map操作:
mapfilter(e=>e._1>1)// Map((2,200), (3,300))
mapfilterKeys(_>1)// Map((2,200), (3,300))
map.map(e=>(e._1*10, e._2)) // Map(10->100,20->200,30->300)
mapmap(e=>e._2)// List(100, 200, 300)
相當于:
map.values.toList
結合Map和Tuple,很容易實現一個key對應的value是組合值的數據結構:
val m = Map(1->("james",20), 2->("qh",30), 3->("qiu", 40))
m(2)._1 // "qh"
m(2)._2 // 30
for((k,(v1,v2))<- m ) printf("%d: (%s,%d)\n", k, v1, v2)
5.3.7.Common operations for maps
What it isWhat it does
valnums=Map("i"->1,"ii"->2)Creates an immutable map (nums.toStringreturnsMap(i->1,ii->2))
nums+("vi"->6)Adds an entry (returnsMap(i->1,ii->2,vi->6))
nums-"ii"Removes an entry (returnsMap(i->1))
nums++List("iii"->3,"v"->5)Adds multiple entries (returnsMap(i->1,ii->2,iii->3,v->5))
nums--List("i","ii")Removes multiple entries (returnsMap())
nums.sizeReturns the size of the map (returns2)
nums.contains("ii")Checks for inclusion (returnstrue)
nums("ii")Retrieves the value at a specified key (returns2)
nums.keysReturns the keys (returns anIteratorover the strings"i"and"ii")
nums.keySetReturns the keys as a set (returnsSet(i,ii))
nums.valuesReturns the values (returns anIteratorover the integers1and2)
nums.isEmptyIndicates whether the map is empty (returns false)
importscala.collection.mutableMakes the mutable collections easy to access
valwords=
mutable.Map.empty[String,Int]Creates an empty, mutable map
words+=("one"->1)Adds a map entry from"one"to1(words.toStringreturnsMap(one->1))
words-="one"Removes a map entry, if it exists (words.toStringreturnsMap())
words++=List("one"->1,
"two"->2,"three"->3)Adds multiple map entries (words.toStringreturnsMap(one->1,two->2,three->3))
words--=List("one","two")Removes multiple objects (words.toStringreturnsMap(three->3))
注:BitSet(collection.immutable.BitSet)和Set類似,但操作更快
var s = Set(1,2,3,4,5) //scala.collection.immutable.Set
var s2 = Set[Int]() //scala.collection.immutable.Set[Int]
//增加元素:
s2 += 1? // Set(1)
s2 += 3? // Set(1,3)
s2 += (2,4) // Set(1,3,2,4)
//刪除元素
Set(1,2,3) - 2 // Set(1,3)
Set(1,2,3) - (1,2) // Set(3)
Set(1,2,3).empty // Set()全部刪除
//判斷是否包含某元素
s(3) // true,集合中有元素3
s(0) // false,集合中沒有元素0
//合并
Set(1,2,3)++Set(2,3,4) // Set(1, 2, 3, 4)
Set(1,2,3)--Set(2,3,4) // Set(1)
運算
例子
交集
Set(1,2,3)&Set(2,3,4) // Set(2,3)
Set(1,2,3)intersectSet(2,3,4)
并集
Set(1,2,3)|Set(2,3,4) // Set(1,2,3,4)
Set(1,2,3)unionSet(2,3,4) // Set(1,2,3,4)
差集
Set(1,2,3)&~Set(2,3,4) // Set(1)
Set(1,2,3)diffSet(2,3,4) // Set(1)
val bs =collection.mutable.BitSet()
bs += (1,3,5) // BitSet(1, 5, 3)
bs ++= List(7,9) // BitSet(1, 9, 7, 5, 3)
bs.clear // BitSet()
5.4.4.Common operations for sets
What it isWhat it does
valnums=Set(1,2,3)Creates an immutable set (nums.toStringreturnsSet(1,2,3))
nums+5Adds an element (returnsSet(1,2,3,5))
nums-3Removes an element (returnsSet(1,2))
nums++List(5,6)Adds multiple elements (returnsSet(1,2,3,5,6))
nums--List(1,2)Removes multiple elements (returnsSet(3))
nums**Set(1,3,5,7)Takes the intersection of two sets (returnsSet(1,3))
nums.sizeReturns the size of the set (returns3)
nums.contains(3)Checks for inclusion (returnstrue)
importscala.collection.mutableMakes the mutable collections easy to access
valwords=
mutable.Set.empty[String]Creates an empty, mutable set (words.toStringreturnsSet())
words+="the"Adds an element (words.toStringreturnsSet(the))
words-="the"Removes an element, if it exists (words.toStringreturnsSet())
words++=List("do","re","mi")Adds multiple elements (words.toStringreturnsSet(do,re,mi))
words--=List("do","re")Removes multiple elements (words.toStringreturnsSet(mi))
words.clearRemoves all elements (words.toStringreturnsSet())
Iterator不屬于集合類型,只是逐個存取集合中元素的方法:
val it = Iterator(1,3,5,7) // Iterator[Int] = non-empty iterator
it foreach println // 1 3 5 7
it foreach println //無輸出
三種常用的使用模式:
val it = Iterator(1,3,5,7) 或者 val it = List(1,3,5,7).iterator
while(it.hasNext) println(it.next)
// 2、使用for
for(e<- Iterator(1,3,5,7)) println(e)
Iterator(1,3,5,7)foreachprintln
Iterator也可以使用map的方法:
Iterator(1,3,5,7) map (10*) toList // List(10, 30, 50, 70)
Iterator(1,3,5,7) dropWhile (5>) toList // List(5,7)
由于Iterator用一次后就消失了,如果要用兩次,需要toList或者使用duplicate:
val (a,b) = Iterator(1,3,5,7) duplicate // a = b = non-empty iterator
又如:
val it = Iterator(1,3,5,7)
val (a,b) = it duplicate
//在使用a、b前,不能使用it,否則a、b都不可用了。
a toList // List(1,3,5,7)
b toList // List(1,3,5,7)
//此時it也不可用了
Scala2.9+引入:
(1 to 10).parforeach println
多運行幾次,注意打印順序會有不同