快学Scala 第13章 集合 - 练习解答

1. 编写一个函数,给定字符串,产出一个包含所有字符的下标的映射。举例来说:indexes("Mississippi")应返回一个映射,让'M'对应集{0},'i'对应集{1,4,7,10},依此类推。
使用字符到可变集的映射。另外,你如何保证集是经过排序的?
回答:使用SortedSet可以保证集是经过排序的。

package ex13_01
 
import scala.collection.mutable.SortedSet
import scala.collection.mutable.Map
 
object Main extends App{
   
  def indexes(s: String): Map[Char,SortedSet[Int]]={
    val map = Map[Char,SortedSet[Int]]()
    for(i <- 0 until s.length()){
      //map  += s(i).toChar -> (map.getOrElse(s(i).toChar, SortedSet(i)) += i)
      map(s(i).toChar) = (map.getOrElse(s(i).toChar, SortedSet(i)) += i)
    }
    map
  }
     
  
val map = indexes("Mississippi")
println(map.mkString(","))
   
}
/* output:
M -> TreeSet(0),s -> TreeSet(2, 3, 5, 6),p -> TreeSet(8, 9),i -> TreeSet(1, 4, 7, 10)
*/






2. 重复前一个练习,这次用字符到列表的不可变映射。
package ex13_02
 
object Main extends App {
 
  def indexes(s: String): Map[Char, List[Int]] = {
    var map = Map[Char, List[Int]]()
    for (i <- 0 until s.length()) {
      val templist = map.get(s(i).toChar)
      if (templist == None) map += s(i).toChar -> List(i)
      else if (!templist.contains(i)) map += s(i).toChar -> (templist.get ::: List(i))
 
    }
    map
  }
 
  val map = indexes("Mississippi")
  println(map.mkString(","))
 
}
/* output:
M -> List(0),i -> List(1, 4, 7, 10),s -> List(2, 3, 5, 6),p -> List(8, 9)
*/





补充阅读: http://stackoverflow.com/questions/27557427/scala-2-11-linkedlist-is-deprecated-what-should-i-use


3. 编写一个函数,从一个整型链表中去除所有零值。
package ex13_03
import scala.collection.mutable.MutableList
object Main extends App {
  def removeZero(lst: MutableList[Int]):MutableList[Int]={
    val mylist = lst.filter( _ != 0)
    mylist
  }
  val a = MutableList(1,2,3,0,5,0,7)
  println(a)
  println(removeZero(a))
}
/* output:
MutableList(1, 2, 3, 0, 5, 0, 7)
MutableList(1, 2, 3, 5, 7)
*/



 

4. 编写一个函数,接受一个字符串的集合,以及一个从字符串到整数值的映射。返回整型的集合,其值为能和集合中某个字符串相对应的映射的值。举例来说,
给定Array("Tom", "Fred", "Harry")和Map("Tom"->3,"Dick"->4,"Harry"->5),返回Array(3,5)。提示:用flatMap将get返回的Option值组合在一起。
package ex13_04
import scala.collection.mutable.MutableList
object Main extends App {
  def getScores(arr: Array[String], map: Map[String, Int]): Array[Int] = {
    val scores = arr.flatMap(map.get(_))
    scores
  }
  val arr = Array("Tom", "Fred", "Harry")
  val map = Map("Tom" -> 3, "Dick" -> 4, "Harry" -> 5)
  val scores = getScores(arr, map)
  println(scores.mkString(","))
}
/* output:
3,5
*/





5. 实现一个函数,作用与mkString相同,使用reduceLeft。
package ex13_05
import scala.collection.mutable.MutableList
object Main extends App {
  def mkString(arr: Array[String], left: String, mid: String, right: String): String = {
    val sb = new StringBuilder()
    sb.append(left)
    sb.append(arr.reduceLeft("%s%s%s".format(_, mid, _)))
    sb.append(right)
    sb.toString()
  }
  val arr = Array("Jonathan", "will", "become", "a", "billionaire", "in", "five", "years")
  println(mkString(arr, "-*-", " ", "-*-"))
}
/* output:
-*-Jonathan will become a billionaire in five years-*-
*/




 
6. 给定整型列表lst,(lst :\ List[Int]())(_ :: _)得到什么?(List[Int]() /: lst)(_ :+ _)又得到什么?如何修改它们中的一个,以对原列表进行反向排列?
package ex13_06
import scala.collection.mutable.MutableList
//def ::(x: A): List[A]
//[user case] Adds an element at the beginning of this list.
//def :+(elem: A): List[A]
//[use case] A copy of the list with an element appended.
object Main extends App {
  val lst = List(1,2,3,4,5,6,7)
  println(lst)
  
  val a = (lst :\ List[Int]())(_ :: _)  // equivalent to  (lst :\ List[Int]())(_ +: _)
  println(a)
  val b = (List[Int]() /: lst)(_ :+ _)
  println(b)
  
  //to reverse
  val c = (lst :\ List[Int]())( (e,r) => r :+ e )
  println(c)
  
  val d = (List[Int]() /: lst)( (r,e) => e +: r )
  println(d)
}
/* output:
List(1, 2, 3, 4, 5, 6, 7)
List(1, 2, 3, 4, 5, 6, 7)
List(1, 2, 3, 4, 5, 6, 7)
List(7, 6, 5, 4, 3, 2, 1)
List(7, 6, 5, 4, 3, 2, 1)
*/




 
7. 在13.11节中,表达式(prices zip quantities) map { p => p._1 * p._2}有些不够优雅。我们不能用(prices zip quantities) map { _ * _},因为 _ * _ 是一个带两个参数的函数,而我们需要的是一个带单个类型为元组的参数的函数,Function对象的tupled方法可以将带两个参数的函数改为以元组为参数的函数。将tupled应用于乘法函数,以使我们可以用它来映射由对偶组成的列表。
package ex13_07
import scala.collection.mutable.MutableList
object Main extends App {
  val prices = List(5.0, 20.0, 9.95)
  val quantities = List(10, 2, 1)
  println((prices zip quantities) map { pair => pair._1 * pair._2 })
  println((prices zip quantities) map { Function.tupled(_ * _) })
}
/* output:
List(50.0, 40.0, 9.95)
List(50.0, 40.0, 9.95)
*/





8. 编写一个函数。将Double数组转换成二维数组。传入列数作为参数。举例来说,Array(1,2,3,4,5,6)和三列,返回Array(Array(1,2,3),Array(4,5,6))。用grouped方法。
package ex13_08
import scala.collection.mutable.MutableList
object Main extends App {
  def to2DArray(arr: Array[Int], cols: Int): Array[Array[Int]] = {
    var result = Array[Array[Int]]()
    for (i <- arr.grouped(3)) result = result :+ i
    result
  }
  val arr = Array(1, 2, 3, 4, 5, 6)
  val result = to2DArray(arr, 3)
  result.foreach(it => println(it.mkString("[", ",", "]")))
}
/* output:
[1,2,3]
[4,5,6]
*/


9. Harry Hacker写了一个从命令行接受一系列文件名的程序。对每个文件名,他都启动一个新的线程来读取文件内容并更新一个字母出现频率映射,声明为:

val frequencies = new scala.collection.multable.HashMap[Char,Int] with scala.collection.mutable.SynchronizedMap[Char,Int]


当读到字母c时,他调用 

frequencies(c) = frequencies.getOrElse(c,0) + 1


为什么这样做得不到正确答案?如果他用如下方式实现呢: 


import scala.collection.JavaConversions.asScalaConcurrentMap
val frequencies:scala.collection.mutable.ConcurrentMap[Char,Int] = new java.util.concurrent.ConcurrentHashMap[Char,Int]

回答: 并发问题,并发修改集合不安全.修改后的代码和修改前的代码没有什么太大的区别. 

10. Harry Hacker把文件读取到字符串中,然后想对字符串的不同部分用并行集合来并发地更新字母出现频率映射。他用了如下代码:

val frequencies = new scala.collection.mutable.HashMap[Char,Int]
for(c <- str.par) frequencies(c) = frequencies.getOrElse(c,0) + 1

为什么说这个想法很糟糕?要真正地并行化这个计算,他应该怎么做呢?(提示:用aggregate) 
回答: 并行修改共享变量,结果无法估计。
package ex13_10_a
import scala.collection.immutable.HashMap
//import scala.collection.mutable.HashMap
//type mismatch; found : scala.collection.mutable.Map[Char,Int] required: scala.collection.mutable.HashMap[Char,Int]
//type mismatch; found : scala.collection.mutable.Map[Char,Int] required: scala.collection.mutable.HashMap[Char,Int]
//Implicit conversion found: c ⇒ ArrowAssoc(c): ArrowAssoc[Char]
object Main extends App {
  def frequence(str: String): HashMap[Char, Int] = {
    val result = str.par.aggregate(HashMap[Char, Int]())(
        {
          (m, c) => 
            m + ( c -> (m.getOrElse(c,0) + 1) )
        }, 
        {
          (m1, m2) =>
          (m1.keySet ++ m2.keySet).foldLeft( HashMap[Char, Int]() ) { 
            (result, k) =>
            result + (k -> (m1.getOrElse(k, 0) + m2.getOrElse(k, 0)))
          }
    })
    result
  }
  //val str = "You were asking me that how deep I've been loving you."
  val str = "Hello"
  println(frequence(str))
}
/* output:
Map(e -> 1, l -> 2, H -> 1, o -> 1)
*/   





你可能感兴趣的:(快学Scala 第13章 集合 - 练习解答)