[关闭]
@EVA001 2017-10-25T16:17:37.000000Z 字数 6715 阅读 359

Scala中的Collectio

Scala


Scala中的immutable Collection 集合

Traversable 遍历
Iterable 迭代
Set无序集合 Sequence序列 Map映射

List[T]

T是类型,由于会自动推导类型,所以不必指明类型

  1. scala> val a = List(1,2,3,4) //定义方法一
  2. a: List[Int] = List(1, 2, 3, 4) //自动推导为Int类型的List
  3. scala> val b = 0::a //定义方法二:连接操作符
  4. b: List[Int] = List(0, 1, 2, 3, 4) //将左边的元素添加到右边List的头部
  5. scala> var c = "x"::"y"::"z"::Nil //Nil是空List
  6. c: List[String] = List(x, y, z)
  7. //上述过程是从右往左连接,步骤如下:
  8. scala> "z"::Nil
  9. res5: List[String] = List(z)
  10. scala> "y"::res5
  11. res6: List[String] = List(y, z)
  12. scala> "x"::res6
  13. res7: List[String] = List(x, y, z)
  14. scala> val d = a:::c //定义方法三:使用:::连接两个List
  15. d: List[Any] = List(1, 2, 3, 4, x, y, z)
  16. //自动推导为Int,String的父类为Any
  17. scala> a.head
  18. res8: Int = 1
  19. scala> d.head //.head返回头元素
  20. res9: Any = 1
  21. scala> c.head
  22. res10: String = x
  23. scala> a.tail //.tail返回除头元素之外的元素
  24. res11: List[Int] = List(2, 3, 4)
  25. scala> d.tail
  26. res12: List[Any] = List(2, 3, 4, x, y, z)
  27. scala> a.isEmpty //.isEmpty返回List是否为空
  28. res13: Boolean = false
  29. scala> Nil.isEmpty
  30. res14: Boolean = true
  31. //利用tail和isEmpty构造循环来实现List的遍历:
  32. scala> def scanf(list: List[Int]):String = {
  33. | if(list.isEmpty) "NULL"
  34. | else list.head.toString+" "+scanf(list.tail)
  35. | }
  36. scanf: (list: List[Int])String
  37. scala> scanf(a)
  38. res15: String = 1 2 3 4 NULL

List的高阶函数 filter:过滤

  1. //将List元素进行过滤
  2. //下面filter参数是一个匿名函数,x代表一个元素,filter会遍历List判断每个元素是否满足条件
  3. scala> a.filter(x => x % 2 ==1)
  4. res17: List[Int] = List(1, 3)
  5. //toList表达式,结果是将当前字符串转为List
  6. scala> "100 Persons".toList
  7. res18: List[Char] = List(1, 0, 0, , P, e, r, s, o, n, s)
  8. //判断是否为数字可以用Character.isDigit(x)方法
  9. scala> "100 Persons".toList.filter(x => Character.isDigit(x))
  10. res20: List[Char] = List(1, 0, 0)
  11. //takeWhile满足条件则取元素,直到!取到某元素才停止
  12. //(类似while循环)下面取元素取到字符‘o’终止,并且不会打印‘o’
  13. scala> "100 Persons".toList.takeWhile(x => x!='o')
  14. res21: List[Char] = List(1, 0, 0, , P, e, r, s)

List的高阶函数 map/flatMap:映射

  1. //对于下面的变量a和c应用映射
  2. scala> a
  3. res22: List[Int] = List(1, 2, 3, 4)
  4. scala> c
  5. res22: List[String] = List(x, y, z)
  6. //map的参数就是一个匿名函数,表明一个转换过程,参数中的匿名函数参数x是List中得每个元素
  7. //使用map实现全部字母大写
  8. scala> c.map(x => x.toUpperCase)
  9. res23: List[String] = List(X, Y, Z)
  10. //参数中的匿名函数参数x可以使用通配符下划线'_'来代替
  11. scala> c.map( _.toUpperCase)
  12. res24: List[String] = List(X, Y, Z)
  13. //同样的filter也可以使用通配符下划线'_'来代替
  14. scala> a.filter( _ % 2 ==1)
  15. res25: List[Int] = List(1, 3)
  16. //通过filter和map来实现对List中过滤后元素的具体操作
  17. //下面是将奇数全部加10
  18. scala> a.filter( _ % 2 ==1).map( _ + 10)
  19. res26: List[Int] = List(11, 13)
  20. //下面是嵌套List
  21. scala> val complex = List( a,List(4,5,6))
  22. complex: List[List[Int]] = List(List(1, 2, 3, 4), List(4, 5, 6))
  23. //对于嵌套List,filter仍然会遍历到最里层的元素并且进行过滤
  24. //但是其返回不会去掉外壳,仍然是个嵌套List
  25. scala> complex.map(x => x.filter( _%2 ==0))
  26. res27: List[List[Int]] = List(List(2, 4), List(4, 6))
  27. //同样,使用下划线也可以通配参数x
  28. scala> complex.map( _.filter( _%2 ==0))
  29. res28: List[List[Int]] = List(List(2, 4), List(4, 6))
  30. //使用flatMap可以将嵌套List“打平”,将返回元素全部放在同一层
  31. //下面就可以取出嵌套List中的偶数,注意,去除了‘外壳’
  32. scala> complex.flatMap( _.filter( _%2 ==0))
  33. res30: List[Int] = List(2, 4, 4, 6)

List的高阶函数 集合的规约操作

把集合的元素通过运算和操作规约为一个值

reduceLeft(op: (T, T) => T )

x1 x2 x3 ... xn
op x3 ... xn
op ... xn
...
op
特性1:参数为一个匿名函数
特性2:规约结果一定是List元素的类型,所以是被经常使用的(相较于foldLeft)

  1. 对于List变量a
  2. scala> a
  3. res33: List[Int] = List(1, 2, 3, 4)
  4. 使用reduceLeft,参数为匿名函数,表示规约的表达式
  5. scala> a.reduceLeft((x,y) => x+y)
  6. res31: Int = 10
  7. 可以使用下划线通配
  8. scala> a.reduceLeft(_+_)
  9. res32: Int = 10

foldLeft(z:U)(op: (U, T) => U )

z x1 x2 ... xn
op x1 ... xn
op ... xn
...
op
特性1:使用柯里化定义
特性2:必须有初始值z
特性3:返回值是初始值z的类型,故不太使用

  1. scala> a
  2. res33: List[Int] = List(1, 2, 3, 4)
  3. //使用foldLeft进行元素的求和,并且初值为0
  4. scala> a.foldLeft(0)((x,y) => x+y)
  5. res34: Int = 10
  6. //使用通配符
  7. scala> a.foldLeft(0)(_+_)
  8. res35: Int = 10
  9. //初值改变后的结果
  10. scala> a.foldLeft(1)(_+_)
  11. res36: Int = 11

惰性求值的类型:Stream 流

  1. //使用to或until来获取range类型
  2. scala> 1 to 10 by 2
  3. res41: scala.collection.immutable.Range = inexact Range 1 to 10 by 2
  4. //until是小于,取不到边界
  5. scala> (1 until 10).toList
  6. res44: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
  7. //to是小于等于,可以取边界
  8. scala> (1 to 10).toList
  9. res45: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
  10. //使用操作符#::来连接定义一个Stream,其中Stream.empty是空流
  11. scala> 1 #:: 2#:: 3#:: Stream.empty
  12. res46: scala.collection.immutable.Stream[Int] = Stream(1, ?)
  13. //惰性求值的特性:由打印可知,只显示和判断第一个元素是什么,其他的用?表示
  14. scala> val s = (1 to 1000).toStream
  15. s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
  16. //获取Stream的第一个元素
  17. scala> s.head
  18. res48: Int = 1
  19. //获取Stream除首元素以外的元素,其返回结果仍然是Stream类型,所以仍然只显示(2, ?)
  20. scala> s.tail
  21. res49: scala.collection.immutable.Stream[Int] = Stream(2, ?)
  22. scala> s.tail.head
  23. res50: Int = 2

Scala中的tuple:元组

  1. //元组的概念,和Python中的元组类似,可以放不用类型的变量
  2. scala> (1,2)
  3. res51: (Int, Int) = (1,2)
  4. //只有两个元素的元组叫pair,可以使用箭头的方式来定义
  5. scala> 1 -> 2
  6. res52: (Int, Int) = (1,2)
  7. //scala自动识别元素类型
  8. scala> val t = (1,'a',"Tom",34.5)
  9. t: (Int, Char, String, Double) = (1,a,Tom,34.5)
  10. //对于一个元组变量,下划线加数字表示第N个元素,t._1表示第一个元素
  11. scala> t._1
  12. res54: Int = 1
  13. //取元素时不能超出下标,否则报错
  14. scala> t._5
  15. <console>:13: error: value _5 is not a member of (Int, Char, String, Double)
  16. t._5
  17. ^

元组的用处:
可以封装函数的返回值,在函数返回多个类型的变量时,可以包装起来一并返回

  1. //下面这个函数通过元组,一并返回输入参数List变量中所有元素的个数、求和、平方和
  2. scala> def _3operate(in:List[Int]):(Int,Int,Int) =
  3. | in.foldLeft((0,0,0))((t,v) => (t._1+1,t._2+v,t._3+v*v)
  4. | )
  5. _3operate: (in: List[Int])(Int, Int, Int)
  6. //调用该函数,可以返回三个值
  7. scala> _3operate(a)
  8. res56: (Int, Int, Int) = (4,10,30)

Scala中的Map

  1. //使用类似元组的箭头来定义一个键值对
  2. scala> val p = Map(1 -> "Tom",9->"Jack")
  3. p: scala.collection.immutable.Map[Int,String] = Map(1 -> Tom, 9 -> Jack)
  4. //按Key取值
  5. scala> p(1)
  6. res58: String = Tom
  7. //判断指定Key是否在Map中
  8. scala> p.contains(1)
  9. res59: Boolean = true
  10. //返回包含全部Key的Set集合
  11. scala> p.keys
  12. res60: Iterable[Int] = Set(1, 9)
  13. //返回包含全部Value的Iterable类型
  14. scala> p.values
  15. res61: Iterable[String] = MapLike.DefaultValuesIterable(Tom, Jack)

涉及的Map相关运算

  1. //使用+号 添加键值对,注意Map不支持混合类型的添加,否则会出错
  2. scala> p + ("name" -> "Kim")
  3. <console>:13: error: type mismatch;
  4. found : (String, String)
  5. required: (Int, ?)
  6. p + ("name" -> "Kim")
  7. ^
  8. //正确添加键值对,注意会按Key值覆写键值对,即Key冲突时丢弃原来的Value
  9. //有冲突的添加
  10. scala> p + (1 -> "Kim")
  11. res63: scala.collection.immutable.Map[Int,String] = Map(1 -> Kim, 9 -> Jack)
  12. //正常的添加
  13. scala> p + (2 -> "Kim")
  14. res65: scala.collection.immutable.Map[Int,String] = Map(1 -> Tom, 9 -> Jack, 2 -> Kim)
  15. //使用-号来删除键值对,注意减的是Key值
  16. scala> p - 1
  17. res70: scala.collection.immutable.Map[Int,String] = Map(9 -> Jack)
  18. //注意添加或删减的结果不能直接通过= 赋值给自己,会报错
  19. scala> p = p -9
  20. <console>:12: error: reassignment to val
  21. p = p -9
  22. ^
  23. //上述的添加和删除都是操作单个元素,下面使用包含键值对的List集合加上++运算符来完成添加拖个键值对
  24. scala> p ++ List(2->"a",5->"b")
  25. res72: scala.collection.immutable.Map[Int,String] = Map(1 -> Tom, 9 -> Jack, 2 -> a, 5 -> b)
  26. //删除多个键值对,注意删除只需要含Key值的List即可
  27. scala> p -- List(1,9,2,5)
  28. res73: scala.collection.immutable.Map[Int,String] = Map()
  29. //可以联合构成表达式
  30. scala> p ++ List(2->"a",5->"b") -- List(2,5)
  31. res74: scala.collection.immutable.Map[Int,String] = Map(1 -> Tom, 9 -> Jack)

函数式编程示例:快速排序

  1. def qSort(a:List[Int]):List[Int] = {
  2. if(a.length < 2) a
  3. else
  4. qSort( a.filter( _ < a.head )) ++
  5. a.filter( _ == a.head ) ++
  6. qSort( a.filter( _ > a.head ))
  7. } //> qSort: (a: List[Int])List[Int]
  8. qSort(List(2,3,5,1,2,8,5,2)) //> res0: List[Int] = List(1, 2, 2, 2, 3, 5, 5, 8)
  9. qSort(List(9,4,8,2,5,1,3,0)) //> res1: List[Int] = List(0, 1, 2, 3, 4, 5, 8, 9)

解释:

首先快排需要一个分割变量,这里直接用a.head即输入List的第一个元素来做分割
其次是归类,每次递归都要分出小于,大于和等于的元素
然后是合并,使用++操作符,把每次的元素拼接起来,即每次调整后的结果
最后是判断递归结束条件:如果当前作为输入的分割后的List元素不足2,那么表示无序调整,排序结束

注意:

这里外层递归中含有两个递归,外层递归即函数的返回的是三部分之和,这并不是尾递归
这个例子是综合了函数式编程、高阶函数、递归等Scala编程思想的体现。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注