集合
可变集合mutable和不可变immutable
Scala 集合类系统地区分了可变的和不可变的集合。可变集合可以在适当的地方被更新或扩展,可以修改,添加,移除一个集合的元素。而不可变集合类,相比之下,永远不会改变。不过,可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变。
集合类都可以在包scala.collection 或scala.collection.mutable,scala.collection.immutable,scala.collection.generic中找到。
-
scala.collection.immutable包是的集合类确保不被任何对象改变。例如一个集合创建之后将不会改变。因此,你可以相信一个事实,在不同的点访问同一个集合的值,你将总是得到相同的元素。。
-
scala.collection.mutable包的集合类则有一些操作可以修改集合。所以处理可变集合意味着你需要去理解哪些代码的修改会导致集合同时改变。
scala默认是不可变集合,如果想使用可变集合,导入collection.mutable包:
import scala.collection.mutable
scala.collection集合类
scala.collection.immutable所有集合类
scala.collection.mutable所有集合类
数组及常用方法
数组声明
scala提供了参数化类型的通用数组类Array[T],T可以升级任意的scala类型,可以通过显示指定类型或者隐式推断来实例化一个数组;
默认是定长数组;
定长数组声明
// Int类型,长度为3,值:1,2,5
// ‘=’后面直接接Array方法,不适用new声明,实际调用的是Array的apply方法
val intArray:Array[Int] = Array[Int](1,2,5)
// String,长度为4,值:a,b,c,d
val strArray:Array[String] = Array[String]("a","b","c","d")
// Int,类型,长度为10
val int2Array:Array[Int] = Array[Int](10)
// 使用new关键字声明,跟VBA前期绑定对象声明类似;
// 比如VBA声明字典对象dim dic as new dictionary
val arr2 = new Array[Int](10)
变长数组声明
import scala.collection.mutable.ArrayBuffer
val arrayBuffer:ArrayBuffer[Int] = new ArrayBuffer[Int]()
增删改查
定长数组只有修改和查询,变长数组支持增删改查方法,两者修改查询方法是一致的;
// 添加元素1
arrayBuffer += 1
// 添加元素3,4,5
arrayBuffer += (3,4,5)
// 拼接数组
arrayBuffer ++= Array(6,7)
arrayBuffer ++= ArrayBuffer(8,9)
// 此时变长数组:arrayBuffer.type = ArrayBuffer(1, 3, 4, 5, 6, 7, 8, 9)
// 删除元素9
arrayBuffer -= 9
// 删除元素8,同样的‘-=’也是一种方法,结果ArrayBuffer(1, 3, 4, 5, 6, 7)
arrayBuffer.-=(8)
// 通过索引删除元素,remove方法会返回删除的元素,类似于python的列表pop方法会返回删除的元素
arrayBuffer.remove(2) // 删除并返回第三位元素:4,索引从0开始
// 修改,第一位元素修改为0
arrayBuffer(0) = 0
// 查询,通过圆括号:(),python是中括号:[]
arrayBuffer(0)
数组遍历
// 循环元素
for(e <- arrayBuffer) println(e)
// 使用foreach方法遍历元素
arrayBuffer.foreach(e => println(e))
// 倒序打印
for(e <- arrayBuffer.reverse) println(e)
// 便利索引访问元素
for(index <- 0 to arrayBuffer.length - 1) println(arrayBuffer(index))
多维数组
多维数字定义
// 示例:2维数组,每一维都是单维数组,三位数组是一样的,再嵌套一维数组即可;
val arr = Array[Array[Int]](Array[Int](1,2,3),Array[Int](4,5,6))
访问
数组访问基本跟java,python一样(scala用的圆括号索引,python中括号);
var arr1 = arr(0)
var element = arr(0)(1)
/**
*arr1: Array[Int] = Array(1, 2, 3)
*element: Int = 2
*/
列表List
- 空列表:Nil
- 任何一个List都是由一个头元素和尾List组成
- 列表是不可变的;
val ls = List(1, 2, 3, 4)
ls.head // 头元素
ls.tail // 尾列表
ls.head :: ls.tail
// List[Int] = List(1, 2, 3, 4)
val ls2 = 1 :: 2 :: Nil // 先从右边计算
// List(1,2)
ls(0) // 1 ,圆括号索引,列表是从0开始的
ls.init // 头列表
ls.last // 尾元素
- 常用方法
//将 0 插入到 lst1 的前面生成一个新的 List
val lst2 = 0 :: lst1
val lst3 = lst1.::(0)
val lst4 = 0 +: lst1
val lst5 = lst1.+:(0)
//将一个元素添加到 lst1 的后面产生一个新的集合
val lst6 = lst1 :+ 3
val lst0 = List(4,5,6)
//将 2 个 list 合并成一个新的 List
val lst7 = lst1 ++ lst0
//将 lst0 插入到 lst1 前面生成一个新的集合
val lst8 = lst1 ++: lst0
//将 lst0 插入到 lst1 前面生成一个新的集合
val lst9 = lst1.:::(lst0)
//采用::及 Nil 进行列表构建
scala> val nums = 1 :: (2 :: (3 :: (4 :: Nil)))
nums: List[Int] = List(1, 2, 3, 4)
//由于::操作符的优先级是从右往左的,因此上一条语句等同于下面这条语句
scala> val nums=1::2::3::4::Nil
nums: List[Int] = List(1, 2, 3, 4)
//判断是否为空
scala> nums.isEmpty
res108: Boolean = false
//取第一个无素
scala> nums.head
res109: Int = 1
//取除第一个元素外剩余的元素,返回的是列表
scala> nums.tail
res114: List[Int] = List(2, 3, 4)
//取列表第二个元素
scala> nums.tail.head
res115: Int = 2
//List 连接操作
scala> List(1,2,3):::List(4,5,6)
res116: List[Int] = List(1, 2, 3, 4, 5, 6)
//取除最后一个元素外的元素,返回的是列表
scala> nums.init
res117: List[Int] = List(1, 2, 3)
//取列表最后一个元素
scala> nums.last
res118: Int = 4
//列表元素倒置
scala> nums.reverse
res119: List[Int] = List(4, 3, 2, 1)
//一些好玩的方法调用
scala> nums.reverse.reverse==nums
res120: Boolean = true
scala> nums.reverse.init
res121: List[Int] = List(4, 3, 2)
scala> nums.tail.reverse
res122: List[Int] = List(4, 3, 2)
//丢弃前 n 个元素
scala> nums drop 3
res123: List[Int] = List(4)
scala> nums drop 1
res124: List[Int] = List(2, 3, 4)
//获取前 n 个元素
scala> nums take 1
res125: List[Int] = List(1)
scala> nums.take(3)
res126: List[Int] = List(1, 2, 3)
//将列表进行分割
scala> nums.splitAt(2)
res127: (List[Int], List[Int]) = (List(1, 2),List(3, 4))
//前一个操作与下列语句等同
scala> (nums.take(2),nums.drop(2))
res128: (List[Int], List[Int]) = (List(1, 2),List(3, 4))
//Zip 操作
scala> val nums=List(1,2,3,4)
nums: List[Int] = List(1, 2, 3, 4)
scala> val chars=List('1','2','3','4')
chars: List[Char] = List(1, 2, 3, 4)
//返回的是 List 类型的元组(Tuple)
scala> nums zip chars
res130: List[(Int, Char)] = List((1,1), (2,2), (3,3), (4,4))
//List toString 方法
scala> nums.toString
res131: String = List(1, 2, 3, 4)
//List mkString 方法
scala> nums.mkString
res132: String = 1234
//转换成数组
scala> nums.toArray
res134: Array[Int] = Array(1, 2, 3, 4)
- 可变序列
import scala.collection.mutable.ListBuffer
//构建一个可变列表,初始有 3 个元素 1,2,3
val lst0 = ListBuffer[Int](1,2,3)
//创建一个空的可变列表
val lst1 = new ListBuffer[Int]
//向 lst1 中追加元素,注意:没有生成新的集合
lst1 += 4
lst1.append(5)
//将 lst1 中的元素最近到 lst0 中, 注意:没有生成新的集合
lst0 ++= lst1
Stay hungry Stay foolish --马中华-- http://blog.csdn.net/zhongqi2513
//将 lst0 和 lst1 合并成一个新的 ListBuffer 注意:生成了一个集合
val lst2= lst0 ++ lst1
//将元素追加到 lst0 的后面生成一个新的集合
val lst3 = lst0 :+ 5
集合Set
- 集合元素是不重复的,可以通过集合元素去重;可变Set需要导入mutable类,默认是不可变集合;
var set = Set(1,2,3,4,4)
// scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4)
set += 88 // 集合对象是不可变的,但是set是var定义的,内存指针可变;
- 可变集合
import scala.collection.mutable
//创建一个可变的 HashSet
val set1 = new mutable.HashSet[Int]()
//向 HashSet 中添加元素
set1 += 2
//add 等价于+=
set1.add(4)
set1 ++= Set(1,3,5)
println(set1)
//删除一个元素
set1 -= 5
set1.remove(2)
println(set1)
- 不可变集合
import scala.collection.immutable.HashSet
val set1 = new HashSet[Int]()
//将元素和 set1 合并生成一个新的 set,原有 set 不变
val set2 = set1 + 4
//set 中元素不能重复
val set3 = set1 ++ Set(5, 6, 7)
val set0 = Set(1,3,4) ++ set1
println(set0.getClass)
- 集合的并集、交集、差集
- 并集 set1 union set2
val set1 = Set(1,2,3) val set2 = Set(2,3,5) set1 union set2 // 会去重
- 交集 set1 intersect set2
- 差集 set1 diff set2
- 并集 set1 union set2
元组Tuple
- 元组是不同类型的值的集合,元素可以是不同类型;不同于数组;
- 使用圆括号定义,通过 ._ 加索引访问,元组的索引是从1开始的;
val tuple = ("zhangsan",18)
// 如果元组只有两个元素也可以使用特殊语法:->
val tuple = "zhangsan" -> 18
tuple._1 // zhangsan,返回第一个元素
- 元组也可以使用模式匹配
tuple match {
case ("zhagnsan",20) => "张三20岁"
case ("lisi",18) => 李四18岁
case _ => "其他人"
}
- 元组可以转化为映射
val arr = Array(("name","zhangsan"),("age",18))
val map = arr.toMap
// map: scala.collection.immutable.Map[String,Any] = Map(name -> zhangsan, age -> 18)
- zip可以将多个值绑定在一起
val arr1 = Array("alice","charlie","kitty")
val arr2 = Array(18,28,26)
val arrZip = arr1.zip(arr2)
arrZip.toMap
映射Map
- 映射的value可以是映射或者函数;
- 同样的,分为可变与不可变,可变需要导入mutable
- 不可变映射无法更新元素,如果需要更新元素,需要定义可变映射;
- map的get方法返回是可选值类型Option(有Some,没有None)
val map = Map("name" -> "张三","age" -> 20)
// map: scala.collection.immutable.Map[String,Any] = Map(name -> 张三, age -> 20)
map("name") // 键值访问,使用圆括号,如果没有会报错;可以先判断是否存在该键
if(map1.contains("name")) println(map("name"))
map filter(kv => kv._1 contains "张") // 筛选键包含“张”的键值对,map.filter 与 map filter在scala方法中是等同的;运算符即方法
map filter(kv => kv._1 startWith "张") // startWith 以 xx字符串开头
// get方法返回Option类型,可以通过getOrElse方法获取对应的值,如果Option是None,返回传入参数值;
map.get("weight").getOrElse("没有找到weight对应的value") // 没有weigth键,返回getOrElse传入的参数值;
- 元素更新
import collection.mutable.Map
val student = Map("name" -> "alice","age" -> 18) // 定义一个Map
// 修改元素:name 为 bob
student("name") = "bob"
// 添加元素
student("weight") = 60
// 也可以使用 += 来添加元素
student += ("height" -> 178)
// 添加多个元素,使用英文逗号分隔
student += ("love" -> "alice","like" -> "basketball")
- 循环遍历元素
for((key,value) <- student) println(s"key is ${key} and value is ${value}")
// 也可以遍历Map的keys和values
student.keys
student.values // Iterable[Any] = HashMap(alice, basketball, 18, bob, 176)
迭代器(Iterator)
- 迭代器不是一个集合,提供了访问集合的方法;
- 两个基本操作:next(返回下一个元素)和hasNext(判断是否有下一个元素)
val iter = Iterator("python","scala","java")
while(iter.hasNext) {
println(iter.next() // 如果有下一个元素,则打印下一个元素;
}
// 也可以使用for遍历循环
for(e <- iter) println(e)
- Iterable有两个方法可以返回迭代器;返回的是原容器(collection)元素的全部子序列,最大子序列作为参数传给这些方法;
- grouped:返回元素增量分块
- sliding:生成一个滑动元素窗口,每次子序列往右滑动一个元素;
val list = List(1,2,3,4,5,6,7)
val g = list grouped 3 // 定义子序列元素为3,每个子序列为3个元素;
// g: Iterator[List[Int]] = non-empty iterator
val s = list sliding 3
// s: Iterator[List[Int]] = non-empty iterator
g.next() // List(1,2,3)
g.next() // List(4,5,6) // 返回增量部分
s.next() // List(1,2,3)
s.next() // List(2,3,4) 往右移了一个元素
字符串常用方法
- java.lang.String类定义的方法列表,可以直接在Scala程序中使用
编号 | 方法 | 描述 |
---|---|---|
1 | char charAt(int index) | 返回指定索引处的字符。 |
2 | int compareTo(Object o) | 将此String 与另一个对象进行比较。 |
3 | int compareTo(String anotherString) | 按字典顺序比较两个字符串。 |
4 | int compareToIgnoreCase(String str) | 按字典顺序比较两个字符串,忽略大小写差异。 |
5 | String concat(String str) | 将指定的字符串连接到该字符串的末尾。 |
6 | boolean contentEquals(StringBuffer sb) | 当且仅当此String 表示与指定的StringBuffer 的字符序列相同时,才返回true 。 |
7 | static String copyValueOf(char[] data) | 返回一个字符串,表示指定的数组中的字符序列。 |
8 | static String copyValueOf(char[] data, int offset, int count) | 返回一个字符串,表示指定的数组中的字符序列。 |
9 | boolean endsWith(String suffix) | 测试此字符串是否以指定的字符串为后缀/结尾。 |
10 | boolean equals(Object anObject) | 将此字符串与指定对象进行比较。 |
11 | boolean equalsIgnoreCase(String anotherString) | 将此String与另一个String进行比较,并忽略大小写。 |
12 | byte getBytes() | 使用平台的默认字符集将此String编码为一系列字节,将结果存储到新的字节数组中。 |
13 | byte[] getBytes(String charsetName) | 使用命名的字符集将此String编码为一系列字节,将结果存储到新的字节数组中。 |
14 | void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) | 将此字符串从srcBegin 到srcEnd 索引处的字符复制到目标字符数组(dst )中。 |
15 | int hashCode() | 返回此字符串的哈希码。 |
16 | int indexOf(int ch) | 返回指定字符第一次在字符串中出现的索引。 |
17 | int indexOf(int ch, int fromIndex) | 返回指定字符以指定的索引开始搜索第一次在字符串内出现的索引。 |
18 | int indexOf(String str) | 返回指定子字符串在字符串内第一次出现的索引。 |
19 | int indexOf(String str, int fromIndex) | 返回从指定的索引开始,指定子串的第一次出现在给定字符串中的索引。 |
20 | String intern() | 返回字符串对象的规范表示。 |
21 | int lastIndexOf(int ch) | 返回指定字符在字符串中最后一次出现的索引。 |
22 | int lastIndexOf(int ch, int fromIndex) | 返回指定字符在给定字符串中的最后一次出现的索引,它从指定的索引开始向后搜索。 |
23 | int lastIndexOf(String str) | 返回指定子字符串在字符串内的最右边出现的索引。 |
24 | int lastIndexOf(String str, int fromIndex) | 返回指定子字符串在给定字符串中最后一次出现的索引,它从指定索引开始向后搜索。 |
25 | int length() | 返回此字符串的长度。 |
26 | boolean matches(String regex) | 测试这个字符串是否与给定的正则表达式匹配。 |
27 | boolean regionMatches(boolean ignoreCase, int toffset, String other, int offset, int len) | 测试两个字符串区域是否相等。 |
28 | boolean regionMatches(int toffset, String other, int offset, int len) | 测试两个字符串区域是否相等。 |
29 | String replace(char oldChar, char newChar) | 返回一个新的字符串,此字符串是使用newChar 替换此字符串中所有出现的oldChar 的结果。 |
30 | String replaceAll(String regex, String replacement | 使用replacement 替换与给定正则表达式(regex )匹配的字符串中的每个子字符串。 |
31 | String replaceFirst(String regex, String replacement) | 用给定的replacement 替换与给定正则表达式(regex )匹配的字符串中的第一个子字符串。 |
32 | String[] split(String regex) | 将此字符串拆分为给定正则表达式的匹配项。 |
33 | String[] split(String regex, int limit) | 将此字符串拆分为给定正则表达式的匹配项。 |
34 | boolean startsWith(String prefix) | 测试此字符串是否以指定的前缀开头。 |
35 | boolean startsWith(String prefix, int toffset) | 测试此字符串是否以指定的前缀开头,指定一个指定的索引。 |
36 | CharSequence subSequence(int beginIndex, int endIndex) | 返回一个新的字符序列,该序列是该序列的子序列。 |
37 | String substring(int beginIndex) | 返回一个新字符串,该字符串是此字符串的子字符串。 |
38 | String substring(int beginIndex, int endIndex) | 返回一个新字符串,该字符串是此字符串的子字符串。 |
39 | char[] toCharArray() | 将此字符串转换为新的字符数组。 |
40 | String toLowerCase() | 使用默认语言环境的规则将此String中的所有字符转换为小写。 |
41 | String toLowerCase(Locale locale) | 使用给定的区域设置的规则将此String中的所有字符转换为小写。 |
42 | String toString() | 此对象(已经是字符串)本身已被返回。 |
43 | String toUpperCase() | 使用默认语言环境的规则将此字符串中的所有字符转换为大写。 |
44 | String toUpperCase(Locale locale) | 使用给定的区域设置的规则将此String中的所有字符转换为大写。 |
45 | String trim() | 返回字符串的副本,省略前导和尾随空格。 |
46 | static String valueOf(primitive data type x) | 返回传递数据类型参数的字符串表示形式。 |
函数组合子
map方法-映射
map:可迭代对象单元素经过函数f映射成新元素迭代对象;
val arr = Array[Int](1,2,3,4,5,5)
// 求和
val arr_sum = arr.sum
// 最大值
val arr_max = arr.max
def add1(a:Int):Int = a + 1
// 传入函数或者方法,返回新的数组
val arr1 = arr.map(f=add1)
// 传入匿名函数
val arr1 = arr.map((num:Int) => num + 1)
python版map;
ls = [1,2,3,4,5] # 创建一个列表
# 定义方法:+1
def add1(a):
return a + 1
# map映射
ls1 = map(add1,ls)
# 遍历打印元素
for e in ls1:
print(e)
import pandas
df = pd.read_csv(file_path) # pandas读取文件
# 新增字段‘map_col’:num列每个元素加1
df['map_col'] = df['num'].map(add1)
reduce方法-聚合
reduce传入函数(形参op)输入参数和输出参数类型必须一致;
reuce分为reduceLeft和reduceRight;前者从集合头部开始操作,后者从集合的尾部开始操作,默认是从左往右;
// 求和sum实现
def sum(a:Int,b:Int):Int = a + b
val arr = Array[Int](1,2,3,4)
arr.reduce(op=sum) // 返回10
// 也可以使用占位符语法简写
arr.reduce(_ + _)
执行步骤:
- sum = 1 + 2
- sum = sum + 3
- sum = sum + 4
- 返回10;
python的reduce方法
from functools import reduce
ls = range(10) # 生成可迭代对象:0-9
res = reduce(lambda x,y : x + y,ls)
fold方法-折叠
第一个参数:(z:B) 初始化的状态值
第二个参数:op:(B,Int) => B
- 逐个把Array中的每个类型的元素合并的初始状态中去;
左折叠:foldleft;右折叠:foldright;
与reduce不一样的是,fold有初始值,输入和输出类型可以不一致;
val intArray = Array[Int](1,2,3,4,5)
# 定义函数,传入字符串,Int,输出字符串
def join(a:String,b:Int):String = s"${a}-${b}"
使用左折叠,如果是右折叠,函数定义,第一参数为Int,第二参数为String类型
val join_str = arr.foldLeft("")(join)
// -1-2-3-4-5
foreach方法-循环
foreach返回是Unit,map方法有返回,经过逻辑处理后结果会覆盖;
val arr = Array[Int](1,2,3,4)
arr.foreach((num:Int) => println(num))
filter过滤-过滤
返回Boolean元素,保留true对应的元素;
val intArray = Array(1,2,3,4,5)
// 选择奇数
val p = (x:Int) => if(x % 2 == 1) true else false
val result:Array[Int] = intArray.filter(p)
println(result.toBuffer)
// 删除第一个负数:-3
val intArray = Array(1,2,-3,-2,5)
var cnt:Int = 0 // 定义全局变量
val result = intArray.filter((x:Int) => {
if(x>=0) true else {
cnt += 1;
if(cnt == 1) false else true
}
})
python的filter方法
ls1 = filter(lambda x:x % 2 == 0,range(100))
for e in ls1:
print(e)
count方法-技术
传入函数返回Bollean,如果是true则计数加1,类似于excel的countif函数;
val intArray = Array(1,2,3,4,5)
// 奇数个数
val p = (x:Int) => if(x % 2 == 1) true else false
val cnt = intArray.count(p)
// length长度
val len(x:Int) => true // 全都返回true
val length = arr.count(len)
python的count方法
ls = [0,1,2,3,4,5,4]
ls.count(4) # 返回2,有两个4,返回list元素出现的个数
sort方法-排序
- sorted:按照默认顺序,字典顺序,从小到大
- sortBy:按照某种规则进行排序,比如数组的长度
- sortWith:自己指定排序规则
// sortde排序
val intArray[Int] = Array[Int](2,1,8,4)
val sortdeArray:Array[Int] = intArray.sorted // 升序排序
val sortdeArray:Array[Int] = intArray.sorted.reverse // 使用reverse反转降序排序
// sortBy排序
// 定义个case class类
case class User(name:String,age:Int,weight:Int)
val userArray = Array[User](
User("alice",18,90),
User("bob",20,120),
User("green",17,130)
)
val userSorted = userArray.sortBy((u:User) => u.age) // 按照用户的年龄升序排序
// 使用sortWith排序:按照体重weigth降序排序,
val userSorted = userArray.sortWith((x:User,y:User) => x.weight > y.weight)
python的sort方法应用于对象本身修改(没有返回),sorted不会对原对象进行修改,返回排序后的对象(有返回);
zip对偶
将两个列表的内容聚合到一个对偶列表中
Array(1,2,3).zip(Array("a","b","c"))
// res0: Array[(Int, String)] = Array((1,a), (2,b), (3,c))
partition切割
将使用给定的谓词函数分隔列表
val arr = Array(1,2,3,4,5,6,7,8)
val arr1 = arr.partition(_ % 2 == 0)
// arr1: (Array[Int], Array[Int]) = (Array(2, 4, 6, 8),Array(1, 3, 5, 7))
arr1._1
// res4: Array[Int] = Array(2, 4, 6, 8)
drop & dropWhile删除
- drop 删除前n个元素
val arr = Array(2, 4, 6, 8)
arr.drop(2)
// res5: Array[Int] = Array(6, 8) 删除了前面两个元素2和4
- dropWhile
dropWhile 从左往右将删除元素,遇到不符合条件元素终止;
val arr = Array(6,2,3,4,5)
arr.dropWhile(_ >=3) // 删除大等于3的元素,这里会删除6,4和5并不是第一个,不会被删除
flatten扁平化拉直
将嵌套结构扁平化为一个层次的集合
val arr = Array(Array(1,2,3),Array(4,5,6))
val arr1 = arr.flatten
// arr1: Array[Int] = Array(1, 2, 3, 4, 5, 6)
flatMap拉直映射
flatMap是一种常用的组合子,结合映射[mapping]和扁平化[flattening]。 flatMap需要一个处理嵌套列表的函数,然后将结果串连起来
val arr = Array(Array(1,2,3),Array(4,5,6))
val arr1 = arr.flatten.map(x => x *2)
// arr1: Array[Int] = Array(2, 4, 6, 8, 10, 12)
find查找
find返回集合中第一个匹配谓词函数的元素。
val arr = Array(1,2,3,4)
arr.find(x => x >= 2)
// Option[Int] = Some(2)
head & last
head:访问第一个元素;last:访问最后一个元素;
val arr = Array(1,2,3,4)
arr.head // 1
arr.last // 4
max & min & sum & product 计算
- max:最大值
- min:最小值
- sum:求和
- product:乘积