Vector
列表是线性的,而向量是树形的,所以向量比列表有更平衡的访问时间(log32(n))。
向量和列表的定义方法类似:
1 2
| val nums = Vector(1, 2, 3, -88) val people = Vector("Bob", "James", "Peter")
|
基本的运算符:
集合的继承层次
1 2 3 4 5 6 7
| Iterable <-| Map | Set | Seq <-| List | Vector | Range | String | Array
|
其中Array
和String
支持和Seq
相同的操作,并且可以隐式转换成Seq
,但它们并不是Seq
的子类,原因是它们来自于Java。
Range
Range
是整数的序列,三个运算符:
1 2 3 4
| val r: Range = 1 until 5 val s: Range = 1 to 5 1 to 10 by 3 6 to 1 by -2
|
更多的Seq
操作符
1 2 3 4 5 6 7 8 9
| xs exists p xs forall p xs zip ys xs unzip xs.flatMap f xs.sum xs.product xs.max xs.min
|
例子:列出1..M和1..N之间所有数组成的数对
1
| (1 to M) flatMap (x => (1 to N) map (y => (x, y)))
|
例子:求数量积
1 2
| def scalarProduct(xs: Vector[Double], ys: Vector[Double]): Double = (xs zip ys).map(xy => xy._1 * xy._2).sum
|
也可以用模式匹配函数值写成:
1 2
| def scalarProduct(xs: Vector[Double], ys: Vector[Double]): Double = (xs zip ys).map{ case (x, y) => x * y }.sum
|
其中,函数值
1
| { case p1 => e1 … case pn => en }
|
等价于
1
| x => x match { case p1 => e1 … case pn => en }
|
练习:判断素数
1
| def isPrime(n: Int): Boolean = (2 until n) forall (d => n % d != 0)
|
练习:给出一个正整数n,找出满足1
1 2 3
| val n = 10 (1 until n) map (i => (1 until i) map (j => (i, j)))
|
会发现返回值类型为IndexedSeq
,实际类型为Vector
。这是因为Vector
和Range
均继承于IndexedSeq
,而Range
不能包含二元组,所以Scala将其换成兄弟类Vector
。
但是期待的返回值类型为二元组的序列,上面的结果并不满足,可以这样解决(设之前结果为xss
):
1
| (xss foldRight Seq[Int]())(_ ++ _)
|
或者用内置方法flatten
:
一个实用的等式:
1
| xs flatMap f = (xs map f).flatten
|
所以可以这样简化:
1 2
| (1 until n) flatMap (i => (i until i) map (j => (i, j)))
|
最终解为:
1 2 3
| (1 until n) flatMap (i => (i until i) map (j => (i, j))) filter ( pair => isPrime(pair._1 + pair._2))
|
这解决了问题,但十分麻烦。
for
表达式
假设persons
是包含类Person
的列表,其中Person
为
1
| case class Person(name: String, age: Int)
|
想取出年龄大于20岁的人,可以这样写:
1
| for ( p <- persons if p.age > 20 ) yield p.name
|
这和下面的相等:
1
| persons filter (p => p.age > 20) map (p => p.name)
|
for
表达式和命令式语言中的循环类似,不同之处在于它将遍历结果生成了列表。
for
表达式的形式:
其中s
是一系列生成器(generator)和过滤器(filter),e
是一个表达式,它的值会在每个遍历中返回。
- 生成器的形式为
p <- e
,其中p
是一个模式,e
是一个值为集合的表达式
- 过滤器的形式为
if f
,其中f
是一个布尔表达式
- 序列必须由生成器开头
- 如果有多个生成器,后面的生成器得比前面的先改变
也可以用大括号{}
代替小括号()
,这时生成器和过滤器序列可以写成多行且不用带分号。
例子:用for
表达式改写之前的练习
1 2 3 4 5
| for { i <- 1 until n j <- 1 until i if isPrime(i + j) } yield (i, j)
|
练习:用for
表达式重写scalarProduct
1 2
| def scalarProduct(xs: List[Double], ys: List[Double]): Double = (for ((x, y) <- xs zip ys) yield x * y).sum
|