scala小练习四

来源:互联网 发布:ubuntu root修改grub 编辑:程序博客网 时间:2024/04/30 01:25

1.一千万个随机数,随机数范围在1到1亿之间,现在要求写出一种算法,将1到1亿之间没有出现的随机数求出来
第一题看这里

2 编 写 一 个 函 数 , 接 收 一 个 字 符 串 集 合 , 以 及 一 个 从 字 符 串 到 整 数 的 映 射
,返回整数集合,其值为能和集合中某个字符串相应的映射值。举例来说,给Array(“Tom”,”Fred”,”Harry”) 和Map(“Tom”->3,”Dick”->4,”Harry”->5),返回Array(3,5)

做了两种实现,一种是map,一种是flatMap(注释部分)

//map将集合中的每个元素处理,并将处理后的结果返回,返回的是option  // 而flatMap与map唯一不一样的地方就是传入的函数在处理完后返回值必须是List  def func(a: Array[String], m: Map[String, Int]): Array[Int] = {    //val res = a.flatMap(m.get(_))//简单的实现    var ans: Array[Int] = Array[Int]()    val r = a.map(m.get(_))    for (a <- r) {      ans = show(a, ans)    }    //从Option中取出Some中数据    def show(r: Option[Int], arr: Array[Int]) = r match {      case None => arr      case Some(s) =>  arr :+ s    }    ans  }

这里写图片描述

3.对给定的整型列表lst,(lst :\ ListInt)(:: )得到的是什么? (ListInt /: lst)(:+)又得到什么?如何修改这两个操作,对原来列表反向操作?

val a=(lst :\ ListInt)(::)
等价于
val c=lst.foldRight(ListInt)(+:)
相当于foldRight,添加lst中的元素到ListInt,初始是一个空List
从右开始操作,每次添加的元素在左侧,所以只能用::或+:

val b=(ListInt/:lst)(:+)
等价于
val d=lst.foldLeft(ListInt)(:+)
foldLeft,从左向右添加元素到列表,所以只能用:+

val lst =List[Int](1,2,3,4,5)    val res1=(lst :\ List[Int]())((x,y)=>y:+x)//正向是x+:y,反过来即可    println("反向:"+res1)    val res2=(List[Int]() /: lst)((x,y)=>y+:x)//正向是x:+y,反过来即可    println("反向:"+res2)

这里写图片描述

4.根据 flatMap 实现一个variance(方差)函数,如果一个序列的平均值m,variance是对序列中的每一个元素x进行math.pow(x-m,2) def variances(xs: Seq[Double]): Option[Double]

def variances(xs: Seq[Double]): Option[Double] = {    val l=xs.length    val m = xs.sum / l    Some(xs.map(x=>math.pow(x-m,2)).sum/l)  }

这里写图片描述

5.统计字符串中字母出现的频率映射,例如字符串 “scalajavajavascript”返回Map[Char,Int]。用aggregate 方法

val a="scalajavajavascript".par.aggregate(HashMap[Char,Int]())(      (k,v)=>{//匿名函数,k打印得kMap(),是要返回的HashMap,v是单个字母        k+(v->(k.getOrElse(v,0)+1))//返回一个HashMap[Char,Int]      }      ,      //当不使用并行的时候,只有上部分就已经可以,这部分直接返回就可以      (k,v)=>(k.keySet++v.keySet).foldLeft((HashMap[Char,Int]())) {//k打印得kMap(),v打印得vMap()\        (res,keys)=>res+(keys->(k.getOrElse(keys,0)+v.getOrElse(keys,0)))      }    )

这里写图片描述

6.写出 ImageReader 的实现类

object work06 {  trait Reader[T] {    //read方法返回值是泛型,通过实现类的时候指定    def read(fileName: String): T  }  class StringReader extends Reader[String]{    def read(fileName: String) = Source.fromFile(fileName, "UTF-8").mkString  }  class ImageReader extends Reader[BufferedImage]{    override def read(fileName: String): BufferedImage = ImageIO.read(new File(fileName))  }}def main(args: Array[String]): Unit = {    val a = new ImageReader    println(a.read("image.png"))  }

拿一张图片简单测试一下
这里写图片描述

真的读到了图片

这里写图片描述

7.定义一个不可变类Pair[T,S],带一个swap 方法,返回数组交换过位置的新对偶。

class Fair[T,S](a:(T,S)){  def swap:(S,T)={    (a._2,a._1)  }}object work07 {  def main(args: Array[String]): Unit = {    val a=new Pair(1,'a')    val b=a.swap    println(b)  }}

这里写图片描述

8 如果我们想把Pair[Person]的第一个组件替换为Student,为什么不需要给 replaceFirst 方法定义一个下界(代码不是答案,答案是文字)

object VarianceDemo {  def makFriends(p: Pair[Person]): Unit = {  }  def main(args: Array[String]) {     val p = new Pair[Student](new Student(), new Student())     //VarianceDemo.makFriends(p)  }}class Pair[T](val first: T, val second: T) {  def replaceFirst(newFirst: T) = new Pair[T](newFirst, second)}class Person {}class Student extends Person {}

答案:
因为Student是Person的子类型,可以直接去替换Person,根本不需要定义下界
那什么时候用下界呢?
下界 R>: T 定义泛型R,R是T的超类
所以下界替换进来的类常常是原类型的超类型
如果我们需要用Person替换Student(超类替换子类),我们需要定义下界,代码如下

object VarianceDemo {  def main(args: Array[String]) {     val p = new Pair[Student](new Student(), new Student())    val a=new Person    p.replaceFirst(a)  }}class Pair[T](val first: T, val second: T) {  def replaceFirst[R>:T](newFirst: R) = new Pair[R](newFirst, second)}class Person {}class Student extends Person {}

如果不定义下界,也可以通过编译,要求返回的 new Pair后面不指定[T],此时返回的类型是Any
由此,可以理解‘界’这个概念

class Pair[T](val first: T, val second: T) {  def replaceFirst[T](newFirst: T) = new Pair(newFirst, second)}

当然有种特别的情况
上述代码,R会被什么具体类型替换,取决于T和 newFirst 的类型。如果 newFirst 的类型刚好是T的基类,,R就直接是 newFirst 的类型。如果 newFirst 的类型不是T的基类,那R就会是T和 newFirst 的类型的共同基类

这道题真是给我整蒙了,甚至让我怀疑人生,因为刚刚看完协变,第一眼就把下界看成协变了,虽然后来看到是人家问的是下界,但协变就一直没从我脑中驱除,思维一直在协变和下界中穿梭,绞尽脑汁想着哪用上协变了啊,其实人家根本没问好嘛,这个过程虽煎熬,但也确实让我把这型变和界理解得更透彻

9 查看 Iterable [+A] 特质。哪些方法使用了类型参数A?为什么在这些方法中类型参数是协变的

foldLeft, foldRight等方法,因为Iterable特质声明类型A为协变

10 定义一个操作符+%,将一个给定的百分比添加到某个值。举例来说120 +% 10 = 132,由于操作符是方法而不是函数,你需要提供一个implicit

object work10 {  //隐式转换的声明必须在要使用的位置之前,否则无效  //因为Double类型中并没有+%这个方法,所以这里把Double类型转换为A类型  implicit def doubleToA(x:Double)=new A(x)  def main(args: Array[String]): Unit = {    val res=120 +% 10    println(res)  }}class A(x:Double){  def +%(y:Double)=x*y*0.01+x}

这里写图片描述