快学Scala笔记(四)

来源:互联网 发布:java bufferedreader 编辑:程序博客网 时间:2024/06/05 18:33

十三、集合

主要的集合特质

scala集合继承层次中的关键特质
Seq是有先后顺序的值的序列,如数组或列表
IndexedSeq允许通过下标访问任何元素,比如ArrayBuffer
Set是一组没有先后次序的值,SortedSet中以某种排序过的顺序访问
Map是一组键值对,SortedMap按照键的排序访问其中的实体
每个Scala集合特质或类都有一个带有apply方法的伴生对象,这个apply方法可以用来构建集合中的实例:
Iterable( 0xFF, 0xFF00, 0xFF0000 )
Set( Color.RED, Color.GREEN, Color.BLUE )
Map( Color.RED -> 0xFF0000, Color.GREEN -> 0xFF00 )
SortedSet( “hello”, “world” )

可变和不可变集合

不可变集合可以安全地共享其引用
Scala优先采用不可变集合,总被引入的scala包和Predef对象里有指向不可变特质的类型别名List、Set和Map

序列

Scala不可变序列
Vector是ArrayBuffer的不可变版本:带下标的序列,支持随机访问。
Vector是以树形结构的形式实现的,每个节点可以有不超过32个子节点。
Range表示一个整数序列,Range对象并不存储所有值,而只是起始值、结束值和增值。
Scala可变序列

列表

Scala中,列表要么是Nil,要么是一个head元素加上一个tail,而tail又是一个列表。
val digits = List(4,2)
digits.head 是 4,digits.tail 是 List(2), digits.tail.tail 是 Nil
:: 操作符从给定的头和尾创建一个新的列表:9 :: List(4,2) ,List(9,4,2)
递归遍历链表

def sum(lst: List[Int]) : Int =   if( lst == Nil ) 0 else lst.head + sum(lst.tail)

模式匹配

def sum(lst: List[Int]) : Int = lst match {  case Nil => 0  case h :: t => h + sum(t)    // h是lst.head, t是lst.tail}

Scala类库已经有sum方法:List(9,4,2).sum

可变列表

LinkedList

// 将负值变为0var lst = scala.collection.mutable.LinkedList(1,-2,7,-9)var cur = lstwhile( cur != Nil ){    if( cur.elem < 0 ) cur.elem = 0    cur = cur.next} 
// 每两个去掉一个var cur = lstwhile( curl != Nil && cur.next != Nil ){    cur.next = cur.next.next    cur = cur.next}

DoubleLinkedList 多带一个prev引用
如果想把列表中的某个节点变成列表中的最后一个节点:
cur.next = LinkedList.empty

集合

集合是不重复元素的集合
Set(2,0,1) + 1 // 无效果
LinkedHashSet(链表),可以记住元素被插入的顺序

val weekdays = scala.collection.mutable.LinkedHashSet("Mo","Tu","We","Th","Fr")

SortedSet(红黑树实现)

scala.collection.immutable.SortedSet(1,2,3,4,5,6)

contains 和 subsetOf

var digits = Set(1,7,2,9)digits contains 0Set(1,2) subsetOf digits

union ( | 或 ++ ), intersect( & ), diff ( &- 或 – )

添加和移除元素的操作符
添加和移除元素的操作符

Iterator特质的重要方法
Iterator方法
Iterator方法2

Seq特质的重要方法
Seq特质的重要方法
Seq特质的重要方法

将函数映射到集合

val names = List("Peter", "Paul", "Mary")names.map( _.toUpperCase ) // List("PETER","PAUL","MARY")
def ulcase(s:String) = Vector( s.toUpperCase(), s.toLowerCase() )names.map(ulcase) // List(Vector("PETER","peter"),...)names.flatMap(ulcase) // List("PETER","peter",...)

collect方法用于偏函数(并没有对所有可能的输入值进行定义的函数,它产出被定义的所有参数的函数值的集合)

"-3+4".collect { case '+' => 1; case '-' => -1 } // Vector(-1,1)

foreach

names.foreach( println )

化简、折叠和扫描

lst.reduceLeft( _ - _ )lst.reduceRight( _ - _ )lst.foldLeft(0)(_ - _)  // (0 :/ lst)(_-_)lst.foldRight(0)(_ - _) // (0 :\ lst)(_-_)(1 to 10).scanLeft(0)(_+_)  // 中间结果的集合(1 to 10).scanRight(0)(_+_)

拉链操作

将两个集合相互对应的元素结合在一起,长度和较短的一致

var prices = List(5.0,20.0)var quantities = List(10,2)prices zip quantities  // List[(Double,Int)]( (prices zip quantities) map { p=>p._1 * p._2 } ) sum

zipAll可以指定较短集合的默认值

List(5.0,20,9.9).zipAll( List(10,2), 0.0, 1 )

zipWithIndex返回对偶的列表,每个对偶中第二个组成部分是每个元素的下标

"Scala".zipWithIndex// Vector( ('S',0), ('c',1), ... )"Scala".zipWithIndex.max._2 

迭代器

可以用iterator方法从集合获得一个迭代器

while (iter.hasNext)     iter.next()
for( elem <- iter )     elem

迭代器是一个“懒”的替代品,有需要时才去取元素,而且很脆弱,每次对next的调用都会改变迭代器的指向。
流(stream)提供的是一个不可变的替代品,流是一个尾部被懒计算的不可变列表,只有当你需要时它才会被计算。

def numsFrom( n : BigInt ): Stream[BigInt] = n #:: numsFrom( n + 1 )

#:: 操作符构建的是一个流
当调用

val tenOrMore = numsFrom(10)

得到一个被显示为

Stream(10, ?)

的流对象,尾部是未被求值的,如果调用

tenOrMore.tail.tail.tail

将会得到

Stream(13,?)

流的方法是懒执行的

val squares = numsFrom(1).map( x => x*x )

将产出

Stream(1,?)

需要squares.tail来强制对下一个元素求值
如果想得到更多,可以调用take,然后用force,强制对所有值求值

squares.take(5).force

可以从迭代器构造一个流,流将缓存访问过的行,允许重新访问它们

val words = Source.fromFile( ".." ).getLines().toStreamwords // Stream(A,?words(5) // Aachenwords // Stream( A, A's, AOL, AOL's, Aachen, ? )

懒视图

view方法产出一个其方法总是被懒执行的集合

val powers = ( 0 until 1000 ).view.map( pow(10,_) )

将产出一个为被求值的集合,当执行powers(100)时,pow(10,100)被计算。和流不同,视图并不缓存,再次调用 powers(100),将重新计算。
和流一样,force方法可以对懒视图强制求值,将得到与原集合相同类型的新集合。
懒集合对于处理需要以多种方式进行变换的大型集合有好处,避免了构建出大型中间集合的需要

(0 to 1000).map(pow(10,_)).map(1/_) // 两个操作分开执行(0 to 1000).view.map(pow(10,_)).map(1/_).force // 两个操作同时执行

与Java集合的互操作

JavaConversions对象提供了用于在Scala和Java之间来回转换的一组方法

import scala.collection.JavaConversions._var props : scala.collection.mutable.Map[String,String] = System.getProperties()props("com.horstmann.scala") = "impatient"// 将调用Properties对象的put("com.horstmann.scala", "impatient")

从Scala到Java集合的转换

线程安全的集合

如果coll是个大型集合

coll.par.sum

会并发的对其求和,par方法产生当前集合的一个并行实现,该实现会尽可能地并行地执行集合方法