一、关键字:
var(variable:可重新指向其他对象)
val(value:只能始终指向同一对象)
① 定义变量
val array: Array[String] = new Array(5)
var stockPrice: Double = 100.0
stockPrice = 200.0 // 指向另一个对象
② 定义一个变量或常量时,也可不指定类型,由编译器自行推断
val xmax, ymax = 100
var greeting, message: String = null
③ 常用类型:Byte、Char Short Int、Long、Float、Double、Boolean。这些都是类,可以执行类方法。
println(1.toString())
println(1.to(10)) // Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
二、数组:Array
① 定长数组 Array
val nums = new Array[Int](10) // 10个元素的数组,所有元素初始化为0
val m = new Array[String](10) // 10个元素的字符串数组,所有元素初始化为null
val s = Array("hello", "hi") // 长度为2的Array[String]一一类型是推断出来的。已提供初始值则不需要new
s.toBuffer // 将数组转换为数组缓冲
② 变长数组 ArrayBuffer
val n = ArrayBuffer[Int]()
val c = new ArrayBuffer[Int]
n += (1, 2, 3, 5) // 用 += 在尾端添加元素
n ++= Array(8, 13, 21) // 用 ++= 追加集合
n.trimEnd(5) // 移除最后5个元素。在数组缓冲的尾端添加或移除元素是一个高效的操作。
n.trimStart(1) // 也可以在任意位置插入或移除元素,但这样的操作并不那么高效,这个位置之后的元素都必须被平移。
n.insert(3, 7, 8, 9) // 第一个数字表示索引位置
n.remove(2, 2) // 第2个参数的含义是要移除多少个元素
n.toArray // 当想要创建一个数组但不知道应该设置的大小时,可以创建一个数组缓冲,然后通过.toArray转换。
③ 遍历数组和数组缓冲
for ( i <- 0 until n.length) // util是Richlnt类的方法,返回所有小于(但不包括)上限的数字。
println(i + ":" + n(i))
for (i <- 0 until (n.length, 2)) // 每两个元素一跳
println(i + ":" + n(i))
for (i <- (0 until n.length) .reverse) // 反向遍历
println(i + ":" + n(i))
for (elem <- a) println(elem) // 如果在循环体中不需要用到数组下标,也可以直接访问数组元素
④ 数组转换
val p = Array(2, 3, 5, 7, 11)
val result = for (elem <- p) yield 2 * elem // for (...) yield循环创建类型与原始集合相同的新集合。结果包含yield之后的表达式,每次选代对应一个。
val result1 = for (elem <- p if elem % 2 == 0) yield 2 * elem // 通过守卫:for中的if对每个偶数元素翻倍,并丢掉奇数元素
val result2 = p.filter(_%2==0).map(2*_) // filter返回满足条件的值,map将所有值合并为一个数组返回
⑤ 内置高效算法
Array(1, 7, 2, 9).sum // 求和
ArrayBuffer("Mary”,”had”,”a”,”little",”lamb").max // 求最大值。.min求最小值。当函数不需要提供参数时,函数名后不需要跟()
val bSorted = p.sorted // 从小到大排序
val bSorted1 = p.sortWith(_>_) // 从大到小排序
scala.util.Sorting.quickSort(p) // 对数组本身进行排序,对数组缓冲不适用
println(p.mkString(" and ")) // 2 and 3 and 5 and 7 and 11
⑥ 多维数组
val matrix= Array.ofDim[Double](3, 4) // 三行,四列
matrix(2)(3) = 42 // 对数组元素赋值
val triangle= new Array[Array[Int]](10) // 指定行数为10的二维数组
for (i <- 0 until triangle.length)
triangle(i) = new Array[Int](i + 1) // 每行的列数都不一样
三、元组:Tuple
① 定义元组
val testTuple = (1, 3.14, "Fred")
② 获取元素
val sec = testTuple._3 // 和数组或字符串中的位置不同,元组的各组元从1开始,而不是0。
③ 模式匹配
val (first, second, third) = testTuple // 将first设为1. second设为3.14. third设为 ”Fred"
val (first1, second1, _) = testTuple // 不需要的元素用 _ 指定
"New York".partition(_.isUpper) // ("NY” , "ew ork")。返回一对字符串,分别是满足条件和不满足条件的字符。
④ 拉链操作
val simbols = Array ("<", "-", ">")
val counts = Array(2, 10, 2)
val pairs = simbols.zip(counts) // 组合成((k,v),(k,v),(k,v))
println(pairs.mkString(" ")) // (<,2) (-,10) (>,2)
val pairs_map = simbols.zip(counts).toMap // 转换为字典
println(pairs_map) // Map(< -> 2, - -> 10, > -> 2)
四、字典:Map
① 构造映射
val scores = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) // 构造出一个不可变的Map[String, Int],其值不能被改变。
val scores1 = scala.collection.mutable.Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) // 可变字典
val scores2 = new scala.collection.mutable.HashMap[String, Int] // 如果想从一个空的映射开始,需要选定一个映射实现并给出类型参数:
val scores3 = Map(("Alice", 10), ("Bob", 3), ("Cindy", 8)) // 也可以这样定义
② 获取映射中的值
val bobsScore = scores3("Bob") // 通过()获取键对应的值,键不存在则抛出异常
val bobsScore1 = if (scores3.contains("Bob")) scores("Bob") else 0 // contains()检查键是否存在
val bobsScore2 = scores3.getOrElse("Bob",0) // 上面代码的简便写法
val bobsScore3 = scores3.get("Bob") // .get()这样的调用返回一个Option对象, 要么是Some(键对应的值), 要么是None。
③ 更新映射中的值(可变字典)
scores1("Bob") = 10 // 更新键 "Bob" 对应的值(需要scores是可变的)
scores1("Fred") = 7 // 增加新的键值对
scores1 += ("Bob" -> 10, "Fred" -> 7) // += 添加多个映射关系
scores1 -= "Alice" // -= 用于移除关系
④ 操作不可变映射
val newScores = scores+ ("Bob" -> 10, "Fred" -> 7) // 操作不可变映射。newScores映射包含了与scores相同的映射关系,"Bob"被更新,"Fred"被添加了进来。
val scores4 = scores - "Alice" // 同理,要从不可变映射中移除某个键,你可以用 - 操作符来获取一个新的去掉该键的映射
⑤ 迭代映射
for ((k, v) <- scores3)
println((k,v))
for (key <- scores3.keySet) // 只遍历键。 .values()遍历值。
println(key)
for ((k, v) <- scores3) yield (v, k) // 反转键值
六、列表:List
① 在Scala中,列表要么是Nil(即空表),要么是一个head元素加上一个tail,而tail又是一个列表
println(List(9, 4, 2).sum) // 15
println((9::4::2::Nil).sum) // 15
② 可变的LinkedList和不可变的List相似,只不过你可以通过对elem引用赋值来修改其头部,对next引用赋值来修改其尾部
val lst = scala.collection.mutable.LinkedList(1, -2, 7, -9)
var cur = lst
// 如下循环将把所有负值都改成零:
while (cur != Nil){
if (cur.elem< 0) cur.elem = 0
cur = cur.next
}
lst.foreach(println _) // 1 0 7 0
lst.foreach(println _) // 空 。上一行代码已经使得lst被全部读取
val a = List(1, 7, 2, 9).reduceLeft(_ - _)
val b = List(1, 7, 2, 9). reduceRight (_ -_)
val q = List(1, 7, 2, 9) .foldLeft(3) (_ - _)
val d = (1 to 10).scanLeft(3)(_ + _)
println(a) // ((1-7)-2)-9 = 1 -7 -2 -9 = -17
println(b) // 1 -(7 -(2 -9)) = 1 -7 + 2 -9 = -13
println(q) // 3 - 1 -7 -2 -9 = -16
println(d) // Vector(3, 4, 6, 9, 13, 18, 24, 31, 39, 48, 58)
// 把相互对应的元素结合在一起,zip方法让你将它们组合成一个个对偶的列表
val prices = List(5.0, 20.0, 9.95)
val quantities = List (10, 2, 1)
val e = prices zip quantities
println(e) // List((5.0,10), (20.0,2), (9.95,1))
// 这样一来对每个对偶应用函数就很容易了
val f = (prices zip quantities) map { p => p._1 * p._2}
println(f) // List(50.0, 40.0, 9.95)
val g = ((prices zip quantities) map { p => p._1 * p._2 }).sum
println(g) // 99.95
// 如果一个集合比另一个短, 那么结果中的对偶数量和较短的那个集合的元素数量相同;zipAll方法让你指定较短列表的缺省值
val h = List(5.0, 20.0, 9.95) zip List(10, 2)
val i = List(5.0, 20.0, 9.95).zipAll(List(10, 2, 7, 9), 0.0, 1)
println(h) // List((5.0,10), (20.0,2))
println(i) // List((5.0,10), (20.0,2), (9.95,7), (0.0,9))
// zip Withindex方法返回对偶的列表,其中每个对偶中第二个组成部分是每个元素的下标
val j = "Scala".zipWithIndex
println(j) // Vector((S,0), (c,1), (a,2), (l,3), (a,4))
val k = "Scala".zipWithIndex.max
println(k) // (l,3)
val l = for ((k, v) <- j) yield (v, k)
println(l) // Vector((0,S), (1,c), (2,a), (3,l), (4,a))
五、集合:Collection
集是不重复元素的集合
和列表不同,集并不保留元素插入的顺序。缺省情况下,集是以哈希集实现的, 其元素根据hashCode方法的值进行组织。在哈希集中查找元素要比在数组或列表中快得多。
// 链式哈希集可以记住元素被插入的顺序。它会维护一个链表来达到这个目的
val weekdays= scala.collection.mutable.LinkedHashSet("Mo", "Tu", "We", "Th", "Fr")
// 如果你想要按照己排序的顺序访问集中的元素,用己排序的集。已排序的集是用红黑树实现的
scala.collection.immutable.SortedSet(1, 2, 3, 4, 5, 6)
// 位集(bit set)是集的一种实现,以一个字节序列的方式存放非负整数。
// contains方法检查某个集是否包含给定的值。subsetOf方法检查某个集当中的所有元素是否都被另一个集包含。
val digits= Set(1, 7, 2, 9)
val x = digits contains 0
println(x) // false
val y = Set(1, 2) subsetOf digits
println(y) // true
// union intersect和diff方法执行通常的集操作
// map方法可以将某个函数应用到组合中的每个元素并产出其结果的集合。
val names = List("Peter", "Paul", "Mary")
val names2 = for (n <- names) yield n.toUpperCase
val names3 = names.map(_.toUpperCase)
println(names2) // List(PETER, PAUL, MARY)。names2=names3
// 如果函数产出一个集合而不是单个值的话,你可能会想要将所有的值串接在一起。如果有这个要求,则用flatMap。
def ulcase (s: String) = Vector(s.toUpperCase(), s.toLowerCase())
val names4 = names.map(ulcase)
val names5 = names.flatMap(ulcase)
println(names4) // List(Vector(PETER, peter), Vector(PAUL, paul), Vector(MARY, mary))
println(names5) // List(PETER, peter, PAUL, paul, MARY, mary)
// collect方法用于偏函数(partial function)一一那些并没有对所有可能的输入值进行定义的函数。它产出被定义的所有参数的函数值的集合
val r = "-3+4".collect{case '+' => 1 ;case '-' => -1}
println(r) // Vector(-1, 1)
// 如果你应用函数到各个元素仅仅是为了它的副作用而不关心函数值的话,那么可以用foreach
names.foreach(println)