@EVA001
2017-10-25T16:17:37.000000Z
字数 6715
阅读 416
Scala
Traversable 遍历
Iterable 迭代
Set无序集合 Sequence序列 Map映射
TreeSet
Sequence
IndexedSeq LinearSeq
IndexedSeq
List,Stream,Quene,Stack
Map
T是类型,由于会自动推导类型,所以不必指明类型
scala> val a = List(1,2,3,4) //定义方法一a: List[Int] = List(1, 2, 3, 4) //自动推导为Int类型的Listscala> val b = 0::a //定义方法二:连接操作符b: List[Int] = List(0, 1, 2, 3, 4) //将左边的元素添加到右边List的头部scala> var c = "x"::"y"::"z"::Nil //Nil是空Listc: List[String] = List(x, y, z)//上述过程是从右往左连接,步骤如下:scala> "z"::Nilres5: List[String] = List(z)scala> "y"::res5res6: List[String] = List(y, z)scala> "x"::res6res7: List[String] = List(x, y, z)scala> val d = a:::c //定义方法三:使用:::连接两个Listd: List[Any] = List(1, 2, 3, 4, x, y, z)//自动推导为Int,String的父类为Anyscala> a.headres8: Int = 1scala> d.head //.head返回头元素res9: Any = 1scala> c.headres10: String = xscala> a.tail //.tail返回除头元素之外的元素res11: List[Int] = List(2, 3, 4)scala> d.tailres12: List[Any] = List(2, 3, 4, x, y, z)scala> a.isEmpty //.isEmpty返回List是否为空res13: Boolean = falsescala> Nil.isEmptyres14: Boolean = true//利用tail和isEmpty构造循环来实现List的遍历:scala> def scanf(list: List[Int]):String = {| if(list.isEmpty) "NULL"| else list.head.toString+" "+scanf(list.tail)| }scanf: (list: List[Int])Stringscala> scanf(a)res15: String = 1 2 3 4 NULL
//将List元素进行过滤//下面filter参数是一个匿名函数,x代表一个元素,filter会遍历List判断每个元素是否满足条件scala> a.filter(x => x % 2 ==1)res17: List[Int] = List(1, 3)//toList表达式,结果是将当前字符串转为Listscala> "100 Persons".toListres18: List[Char] = List(1, 0, 0, , P, e, r, s, o, n, s)//判断是否为数字可以用Character.isDigit(x)方法scala> "100 Persons".toList.filter(x => Character.isDigit(x))res20: List[Char] = List(1, 0, 0)//takeWhile满足条件则取元素,直到!取到某元素才停止//(类似while循环)下面取元素取到字符‘o’终止,并且不会打印‘o’scala> "100 Persons".toList.takeWhile(x => x!='o')res21: List[Char] = List(1, 0, 0, , P, e, r, s)
//对于下面的变量a和c应用映射scala> ares22: List[Int] = List(1, 2, 3, 4)scala> cres22: List[String] = List(x, y, z)//map的参数就是一个匿名函数,表明一个转换过程,参数中的匿名函数参数x是List中得每个元素//使用map实现全部字母大写scala> c.map(x => x.toUpperCase)res23: List[String] = List(X, Y, Z)//参数中的匿名函数参数x可以使用通配符下划线'_'来代替scala> c.map( _.toUpperCase)res24: List[String] = List(X, Y, Z)//同样的filter也可以使用通配符下划线'_'来代替scala> a.filter( _ % 2 ==1)res25: List[Int] = List(1, 3)//通过filter和map来实现对List中过滤后元素的具体操作//下面是将奇数全部加10scala> a.filter( _ % 2 ==1).map( _ + 10)res26: List[Int] = List(11, 13)//下面是嵌套Listscala> val complex = List( a,List(4,5,6))complex: List[List[Int]] = List(List(1, 2, 3, 4), List(4, 5, 6))//对于嵌套List,filter仍然会遍历到最里层的元素并且进行过滤//但是其返回不会去掉外壳,仍然是个嵌套Listscala> complex.map(x => x.filter( _%2 ==0))res27: List[List[Int]] = List(List(2, 4), List(4, 6))//同样,使用下划线也可以通配参数xscala> complex.map( _.filter( _%2 ==0))res28: List[List[Int]] = List(List(2, 4), List(4, 6))//使用flatMap可以将嵌套List“打平”,将返回元素全部放在同一层//下面就可以取出嵌套List中的偶数,注意,去除了‘外壳’scala> complex.flatMap( _.filter( _%2 ==0))res30: List[Int] = List(2, 4, 4, 6)
把集合的元素通过运算和操作规约为一个值
x1 x2 x3 ... xn
op x3 ... xn
op ... xn
...
op
特性1:参数为一个匿名函数
特性2:规约结果一定是List元素的类型,所以是被经常使用的(相较于foldLeft)
对于List变量ascala> ares33: List[Int] = List(1, 2, 3, 4)使用reduceLeft,参数为匿名函数,表示规约的表达式scala> a.reduceLeft((x,y) => x+y)res31: Int = 10可以使用下划线通配scala> a.reduceLeft(_+_)res32: Int = 10
z x1 x2 ... xn
op x1 ... xn
op ... xn
...
op
特性1:使用柯里化定义
特性2:必须有初始值z
特性3:返回值是初始值z的类型,故不太使用
scala> ares33: List[Int] = List(1, 2, 3, 4)//使用foldLeft进行元素的求和,并且初值为0scala> a.foldLeft(0)((x,y) => x+y)res34: Int = 10//使用通配符scala> a.foldLeft(0)(_+_)res35: Int = 10//初值改变后的结果scala> a.foldLeft(1)(_+_)res36: Int = 11
//使用to或until来获取range类型scala> 1 to 10 by 2res41: scala.collection.immutable.Range = inexact Range 1 to 10 by 2//until是小于,取不到边界scala> (1 until 10).toListres44: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)//to是小于等于,可以取边界scala> (1 to 10).toListres45: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)//使用操作符#::来连接定义一个Stream,其中Stream.empty是空流scala> 1 #:: 2#:: 3#:: Stream.emptyres46: scala.collection.immutable.Stream[Int] = Stream(1, ?)//惰性求值的特性:由打印可知,只显示和判断第一个元素是什么,其他的用?表示scala> val s = (1 to 1000).toStreams: scala.collection.immutable.Stream[Int] = Stream(1, ?)//获取Stream的第一个元素scala> s.headres48: Int = 1//获取Stream除首元素以外的元素,其返回结果仍然是Stream类型,所以仍然只显示(2, ?)scala> s.tailres49: scala.collection.immutable.Stream[Int] = Stream(2, ?)scala> s.tail.headres50: Int = 2
//元组的概念,和Python中的元组类似,可以放不用类型的变量scala> (1,2)res51: (Int, Int) = (1,2)//只有两个元素的元组叫pair,可以使用箭头的方式来定义scala> 1 -> 2res52: (Int, Int) = (1,2)//scala自动识别元素类型scala> val t = (1,'a',"Tom",34.5)t: (Int, Char, String, Double) = (1,a,Tom,34.5)//对于一个元组变量,下划线加数字表示第N个元素,t._1表示第一个元素scala> t._1res54: Int = 1//取元素时不能超出下标,否则报错scala> t._5<console>:13: error: value _5 is not a member of (Int, Char, String, Double)t._5^
元组的用处:
可以封装函数的返回值,在函数返回多个类型的变量时,可以包装起来一并返回
//下面这个函数通过元组,一并返回输入参数List变量中所有元素的个数、求和、平方和scala> def _3operate(in:List[Int]):(Int,Int,Int) =| in.foldLeft((0,0,0))((t,v) => (t._1+1,t._2+v,t._3+v*v)| )_3operate: (in: List[Int])(Int, Int, Int)//调用该函数,可以返回三个值scala> _3operate(a)res56: (Int, Int, Int) = (4,10,30)
//使用类似元组的箭头来定义一个键值对scala> val p = Map(1 -> "Tom",9->"Jack")p: scala.collection.immutable.Map[Int,String] = Map(1 -> Tom, 9 -> Jack)//按Key取值scala> p(1)res58: String = Tom//判断指定Key是否在Map中scala> p.contains(1)res59: Boolean = true//返回包含全部Key的Set集合scala> p.keysres60: Iterable[Int] = Set(1, 9)//返回包含全部Value的Iterable类型scala> p.valuesres61: Iterable[String] = MapLike.DefaultValuesIterable(Tom, Jack)
涉及的Map相关运算
//使用+号 添加键值对,注意Map不支持混合类型的添加,否则会出错scala> p + ("name" -> "Kim")<console>:13: error: type mismatch;found : (String, String)required: (Int, ?)p + ("name" -> "Kim")^//正确添加键值对,注意会按Key值覆写键值对,即Key冲突时丢弃原来的Value//有冲突的添加scala> p + (1 -> "Kim")res63: scala.collection.immutable.Map[Int,String] = Map(1 -> Kim, 9 -> Jack)//正常的添加scala> p + (2 -> "Kim")res65: scala.collection.immutable.Map[Int,String] = Map(1 -> Tom, 9 -> Jack, 2 -> Kim)//使用-号来删除键值对,注意减的是Key值scala> p - 1res70: scala.collection.immutable.Map[Int,String] = Map(9 -> Jack)//注意添加或删减的结果不能直接通过= 赋值给自己,会报错scala> p = p -9<console>:12: error: reassignment to valp = p -9^//上述的添加和删除都是操作单个元素,下面使用包含键值对的List集合加上++运算符来完成添加拖个键值对scala> p ++ List(2->"a",5->"b")res72: scala.collection.immutable.Map[Int,String] = Map(1 -> Tom, 9 -> Jack, 2 -> a, 5 -> b)//删除多个键值对,注意删除只需要含Key值的List即可scala> p -- List(1,9,2,5)res73: scala.collection.immutable.Map[Int,String] = Map()//可以联合构成表达式scala> p ++ List(2->"a",5->"b") -- List(2,5)res74: scala.collection.immutable.Map[Int,String] = Map(1 -> Tom, 9 -> Jack)
def qSort(a:List[Int]):List[Int] = {if(a.length < 2) aelseqSort( a.filter( _ < a.head )) ++a.filter( _ == a.head ) ++qSort( a.filter( _ > a.head ))} //> qSort: (a: List[Int])List[Int]qSort(List(2,3,5,1,2,8,5,2)) //> res0: List[Int] = List(1, 2, 2, 2, 3, 5, 5, 8)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编程思想的体现。