版权属于: Postbird - There I am , in the world more exciting!
原文地址: http://www.ptbird.cn/kuaixue-scala-answer-chapter-12.html
转载时必须以链接形式注明原始出处及本声明。
最近看了看《快学scala》,比较好的点在于这本书每一章后面都有一些练习,可以自己去做一下,对于掌握知识来讲还是不错的(像是以前上学后面的习题一样)。
我不知道哪里有答案,也没有认真找过,就自己做了做。
iteye上有一个人写了前几章的答案,可以参考一下,链接为:http://ivaneye.iteye.com/blog/1843331,遗憾的是这个人只写到第九章,我上面的链接也是第九章,后面就没有了。
为什么我要写第12章?
其实前面的练习我都没有特别认真的做,简单写了写,也参照了一下上面的博客(非常感谢),12章是将简单的高阶函数,对于scala这样讲函数式与面向对象很好的结合的语言,高阶函数是必须掌握的内容,所以我也就花心思做了做练习,并且将10个题的答案写了下来。
我的答案就正确吗?
只能说,我根据题目都按照他的思想实现了内容,至于答案是不是最优的,这应该是不可能的。
仅供参照。
如果有不同,欢迎指点。
题目简单提一下,可以参照书籍。
练习1:利用函数的函数参数生成对偶集合
这个没什么,就是简单地函数参数的利用而已。
//第一题 LX12_1
def values(func:(Int)=>Int,low:Int,high:Int){
for( i<- low to high){
println("("+i+","+func(i)+")")
}
}
//调用函数
def func(x:Int):Int=x*x
values(func,-5,5)
这个只要每次返回一个大的值就可以,我用了 if比较大小 懒。。。。
//第二题 LX12_2
def getMaxByReduceLeft(arr:Array[Int]): Int ={
arr.reduceLeft((a,b)=>{if(a > b) a;else b})
}
//调用函数
val arr=Array(1,2,3,4,5,6,7,2,3,5)
println(getMaxByReduceLeft(arr))
练习3:使用to和reduceLeft实现阶乘,不得使用循环和递归
我觉得我这个写的有点问题,我默认的类型是Long的,但是练习4说要考虑n<1的情况
因此我就无视了
第三和第四题都是有点问题的
//第三题 LX12_3
//只考虑 n>1 且 n为Int的情况的解决
def getFactorialByReduceLeft(num:Long):Long={
(1:Long).to(num).reduceLeft(_*_)
}
//调用函数
println(getFactorialByReduceLeft(10:Long))
练习5:输出在给定输入序列中给定函数的最大值,不得使用循环和递归
这个提示和第二题唯一的不同就是比较的函数的大小而已,不过我用了一个ans一直记录函数最大值,这样子最后才能返回需要的也就是函数的最大值
//第五题 LX12_5
def LX12_5(func:(Int)=>Int,inputs:Seq[Int]):Int={
var ans:Int=0
inputs.reduceLeft((a,b)=>{
// println(func(a)+" "+func(b))
if(func(a) > func(b)){ans=func(a); a}
else {ans=func(b); b}
})
ans
}
//测试函数
def func2(x:Int)=10 *x-x*x
println(LX12_5(func2,1 to 10))
练习6:对比第5题,返回函数的最大值时的输入值,不得使用循环和递归
第五题刚好反过来,需要求最大值时候的输入值,只要让ans记录输入值就行了
//第六题 LX12_6
//一个意思 没什么的
def LX12_6(func:(Int)=>Int,input:Seq[Int]):Int ={
input.reduceLeft((a,b)=>{
// println(func(a)+" "+func(b))
if(func(a) > func(b))a
else b
})
}
//测试函数
def func3(x:Int)=10*x
println(LX12_6(func3,1 to 3))
练习7:创建一个函数返回一个能接受对偶(tuple2)为参数的函数并能接受一个计算的函数参数
这个题很有意思,首先,通过 zip操作得到的实际上是一个元祖为基础的vector,而进行map的时候不能简单地map(_+_),因为他不是两个int,而是一个tuple2
创建的函数要求能够在map中去处理,看代码。。。
//第七题 LX12_7
val pairs=(1 to 10) zip (11 to 20)
//我们都知道map可以每次去处理一个值,但是他不接受tuple
//所以ajustToPair刚好解决这个问题,能够接受tuple2,并返回另一个函数
def ajustToPair(func:(Int,Int)=>Int)=(pair:Tuple2[Int,Int])=>{func(pair._1,pair._2)}
//测试函数
println(pairs.map(i=>ajustToPair(_ + _)(i)))
练习8:利用corresponds和科里化比较字符串序列中每个字符的长度是否和一个整形数组中的值一一对应
这个看看书上的例子很容易就写出来了
//第八题LX12_8
val tmpStr=Array("hello","scala","postbird")
val tmpLen=Array(5,5,8)
// val tmpLen=Array(5,5,7)
println(tmpStr.corresponds(tmpLen)(_.length==_))
练习9:不使用科里化实现第八题
题目说上一题应该是第七题,也就是使用 zip集合map来实现
当然还是要借助我们的ajustToPair函数的
最后我用了res来记录,使用foreach结合 && 操作记录最后是false和true
我写的比较麻烦,但是也实现了。不知到有没有别的方式
//第九题LX12_9
//不知道前一个联系指的是 7 还是8 应该是 7 因为7用了zip
//然后用了比较麻烦的实现
val tmpStr_2=Array("hello","scala","postbird")
val tmpLen_2=Array(5,5,8)
// val tmpLen_2=Array(5,5,7)
val pairs_2=tmpStr_2 zip tmpLen_2
def ajustToPair_2(func:(String,Int)=>Boolean)=(pair:Tuple2[String,Int])=>{func(pair._1,pair._2)}
var res:Boolean=true
pairs_2.map(i=>ajustToPair_2(_.length == _)(i)).foreach(b=>res=res&&b)
println(res)
练习10:参照until根据控制抽象实现一个unless
一定是需要换名调度,另外需要科里化,不然太麻烦
但实际上 换名调度我只是了解个皮毛
//第十题 LX12_10
//换名调用和科里化是需要的 可以最简洁的表示
//省略了() 冒号和 => 的空格是一定要有的
def unless(condition: =>Boolean)(block: =>Unit){
if(condition){
block
unless(condition)(block)
}
}
//测试函数
//意思是:除非 到了2,否则就一直输出
var tmpNum=10
unless(tmpNum!=2){
tmpNum-=1
println(tmpNum)
}
代码:
我在码云存了一个代码片段
git@osc:https://git.oschina.net/postbird/codes/uomv9j0d13lfs2e5hxyar77