分布式机器学习:如何快速从Python栈过渡到Scala栈 (2)

for:

println(1 to 10) println(1 until 10) for (i <- 1 to 10) print(i+"\t") println() for (i <- 1 until 10) print(i+"\t") println() // 遍历数组中的元素,类似java的增强for // 可以看到数组中元素可以不同类型 for (arr <- Array('n',1,3.45,true,"nemo")) print(arr+"\t") println() // for循环高级技巧:单个for中有多个变量,每个生成器都带过滤条件 // 效果就是嵌套for循环 for (i <- 1 to 10 if i%2==0; j <- Array("n","e","m","o") if j!="e") print(i+":"+j+"\t") println() // for推导式,循环体以yield开始会构建一个集合返回 val vec = for (i <- 1 to 10) yield i*10 println(vec) for (i <- vec) print(i+"\t") println()

for循环时Scala比较有特点的一部分:

支持n to m和n until m两种方式,区别是使用until时循环不包含m,算是很贴心的小改动,可读性比java和python都强一些;

for循环支持生成器、集合、range等类型中遍历,类似java的普通循环和增强for循环的结合,for (item <- 1 to 10)、for (item <- Array('a','b','c'));

高级for循环技巧:每层循环带过滤条件,嵌套循环写在一个for内;

Scala的for循环也支持类似python列表推导式的方法:for (1 <- 1 to 10) yield i*10;

函数

准确的说,在Scala中函数方法不完全等价,所谓的方法是类的一部分,而函数则是一个对象,可以赋值给一个变量,这里就不纠结啦;

// 函数:一行函数,返回值类型可以不写,此时自动推断 def func(x:Int, y:Int): Int = x+y println(func(2,3)) // 但是递归函数的返回值类型必须手动指定 def fib(f:Int): Int = if(f==0) 0 else if(f==1) 1 else if(f==2) 2 else fib(f-2)+fib(f-1) println(fib(1),fib(2),fib(3),fib(4),fib(5)) // 在scala中,函数也是一种变量类型,因此也同样可以赋值为某个常量或者当作另一个函数的参数 val f = (x:Int) => x*10 // 简易函数就是lambda表达式 println(f) def ff(k:(Int) => Int,x:Int,y:Int): Int = k(x)+k(y) println(ff(f,3,5)) // def的方法转函数 println(fib _) // fib本身是def定义的方法,甚至不能直接print

上面介绍的其实都是函数而不是方法:

定义一个变量,将一个函数赋值给它;

将一个函数变量作为入参传入到另一个函数中;

这里对于函数的理解可以想象数学中的函数,数学中的函数嵌套、组合的过程就是Scala中的函数互相作为参数传递的过程;

基本集合类型

一般高级语言中支持的集合类型都是类似的:数组列表字典元组等,Scala也不例外,这些基本上也满足日常需求;

一个需要注意的点:Scala中的这些集合类型基本都分为定长变长这两种,默认情况下都是定长的,可以通过scala.collection.mutable.xxx来导入对应的变长版本,主要区别在于当集合长度改变时是否需要重新创建一个新的集合对象;

数组 val arr = new Array[Int](8) // 长度为8,全是0的不可变数组 println(arr) // 直接打印数组看不到其内部元素,只能看到它的地址 println(arr.toBuffer) // 通过toBuffer方法转为数组缓冲区 val arr2 = Array[Int](8) // 注意这里没用new println(arr2) println(arr2.toBuffer) val arr3 = Array(0,1.2f,true,'h',"nemo") // 指定内容的定长数组 println(arr3(0),arr3(1),arr3(3)) // 通过(n)访问数组元素,下标从0开始 // 变长数组,不改变变量的前提下依然可以通过+=,++=来扩展数组 import scala.collection.mutable.ArrayBuffer val marr = ArrayBuffer[Int]() marr += 1 marr += (2,3,4) marr ++= Array(5,6,7) marr ++= ArrayBuffer(8,9) marr.insert(0,0) marr.remove(0) println(marr) // 使用for遍历 for (item <- marr) print(item+"\t") println() for (idx <- (0 until marr.length).reverse) // reverse可以反转Range内的元素 print(idx+":"+marr(idx)+"\t") println() // 对于数组,取出其全部偶数,再乘以10返回新数组 // 写法1:也是一般的程序写法,这个过程中其实是将需求转换为程序思想 var marr2 = Array(1,2,3,4,5,6,7,8,9,10) marr2 = for (i <- marr2 if i%2==0) yield i*10 println(marr2.toBuffer) // 写法2:更加scala,面向函数,可读性更强,不需要维护那个i,循环会执行两次,先过滤,再映射 marr2 = Array(1,2,3,4,5,6,7,8,9,10) marr2 = marr2.filter(_%2==0).map(_*10) println(marr2.toBuffer) // 数组的一些常用方法,注意scala中函数调用没有参数时可以不写() println(marr2.sum,marr2.max,marr2.sorted.toBuffer)

从数组上看差异:

首先一个小特点在于直接打印数组对象只能看到内存地址,要看到内容需要打印arr.toBuffer;

数组内的元素可以是不同类型的;

通过arr(n)访问元素,下标从0开始;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyzfsz.html