是否有更好或更实用的方法来比较Scala中地图中的2个值?

时间:2017-01-05 18:58:50

标签: scala functional-programming maps comparison

我有一些功能,允许用户比较地图中包含的两个团队。地图中包含的数据是从一个文本文件中读取的,该文件包含有关橄榄球队的信息以及过去5个赛季的积分。数据存储为Map [String,List [Int]]:

Manchester United, 72, 86, 83, 90, 94
Manchester City, 80, 84, 91, 77, 88
Chelsea, 76, 85, 92, 87, 84
Arsenal, 70, 79, 81, 76, 83
Liverpool, 69, 77, 80, 73, 79

以下功能允许用户输入两个团队的名称,并比较两个团队最近(最后)积分的差异。

 val teamdata = readTextFile("teams.txt")

 //User presses 2 on keyboard, this invokes menuCompareTeams which invokes compareTeams
 def menuOptionTwo(): Boolean = {
   //2 - compare 2 teams selected by the user
   menuCompareTeams(compareTeams)
   true
 }

 //Function which displays the results of compareTeams
 def menuCompareTeams(f: (String, String) => ((String, Int), (String, Int), String)) = {
        val input = f(readLine("Enter first team to compare>"),
                      readLine("Enter second team to compare>"))
        println(s"""|Team 1: ${input._1._1} - Points: ${input._1._2}
                    |Team 2: ${input._2._1} - Points: ${input._2._2}
                    |${input._3}""".stripMargin)           
 }

 ///Function which compares the 2 teams - invoked by menuCompareTeams
 def compareTeams(team1: String, team2: String): ((String, Int), (String, Int), String) = {
   def lastPoints(list: List[Int]): Int = list match {
     case Nil => throw new Exception("Empty list")
     case h :: Nil => h
     case _ :: tail => lastPoints(tail)
   }

   val team1Points = teamdata.get(team1) match{
     case Some(p) => lastPoints(p)
     case None => 0
   }

   val team2Points = teamdata.get(team2) match{
     case Some(p) => lastPoints(p)
     case None => 0
   }

   val pointsComparison = if(team1Points > team2Points){
     "The team who finished higher is: " + team1 + ", their total points tally for last season was: " + team1Points + ". There was a difference of " + (team1Points-team2Points) + " points between the two teams."
   }
   else if(team1Points == team2Points){
     "The teams had equal points last season: " + (team1Points|team2Points)
   }
   else{
     "The team who finished higher is: " + team2 + ", their total points tally for last season was: " + team2Points + ". There was a difference of " + (team2Points-team1Points) + " points between the two teams."
   }

   ((team1, team1Points), (team2, team2Points), pointsComparison)

 }

E.g。用户进入“曼联”和“曼城”时的正确输出如下所示:

  第1组:曼联 - 积分:94

     

第2队:曼城 - 积分:88

     完成更高的球队是:曼联,他们上赛季的总分数为:94。两队之间的差距为6分。

对于2支队伍的比较,是否有更好或更实用的方法来做我目前正在做的事情?

编辑:我根据Alex的建议编辑了这个问题。

1 个答案:

答案 0 :(得分:0)

“更多功能”

你所拥有的一个“副作用”是为空列表抛出异常。如果这确实是一个特例,那么lastPoints应该返回Try[Int]。除此之外,您保持参照透明度,使用模式匹配,并使用递归函数,这样您就无法获得“更多功能”。

<强> “更好的”

您可以在lastPoints中使用List#lastOption(假设您不会抛出异常),而不是自己编写:

val lastPoints = (_ : List[Int]).lastOption

然后可以按如下方式使用:

val getPoints = 
  (team : String) => teamdata.get(team)
                             .flatMap(lastPoints)
                             .getOrElse(0)

val team1Points = getPoints(team1)
val team2Points = getPoints(team2)

一般来说,在尝试“自己动手”之前,我总是去寻找一种能解决我问题的收集方法。依靠lastOptionflatMapgetOrElse,潜伏着虫子的地方就更少了。