2017-01-05 14 views
0

У меня есть функции, которые позволяют пользователю сравнивать две команды, содержащиеся в карте. Данные, содержащиеся на карте, считываются из текстового файла, который содержит информацию о футбольных командах и их подсчетах очков за последние 5 сезонов. Данные хранятся в виде карты [String, List [Int]]:Есть ли лучший или функциональный способ сравнить 2 значения на карте в Scala?

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. Правильный выход, когда пользователь вводит 'Манчестер Юнайтед' и 'Манчестер Сити' будет показано ниже:

Team 1: Манчестер Юнайтед - Очки: 94

Команда 2: Манчестер Сити - Очки: 88

Команда, вышедшая на титул: «Манчестер Юнайтед», их общая сумма очков за прошлый сезон была: 94. Между двумя командами разница составила 6 очков.

Есть ли лучший или функциональный способ сделать то, что я делаю сейчас, для сравнения 2 команд?

EDIT: Я отредактировал вопрос, основанный на предположении Алекса.

+0

Очень длинный текст с несколькими вопрос. Я хотел бы предложить вам разделить его на несколько вопросов. Начните с основ: как лучше сравнить две команды по их результатам в сезоне. –

+0

@AlexFruzenshtein Спасибо за отзыв, я отредактировал вопрос на основе вашего предложения. – ASGD

ответ

0

«Более функциональный»

Один «побочный эффект» у вас есть, бросает исключение для пустых списков. Если это действительно исключительный случай, то lastPoints должен вернуть Try[Int]. Помимо этого вы поддерживаете ссылочную прозрачность, используйте сопоставление с образцом и используете рекурсивные функции, чтобы вы не могли получить «более функциональный».

"Лучше"

Вы можете использовать List#lastOption в lastPoints (предполагая, что вы не бросать исключения) вместо того, чтобы писать свои собственные:

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

которые затем могут быть использованы следующим образом:

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

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

В общем, я всегда ищу метод сбора, который решает перед тем, как попытаться «опрокинуть мои собственные». Опираясь на lastOption, flatMap и getOrElse, мест для жуков меньше.