Говоря строго о том, как форматировать этот код, без внесения каких-либо структурных изменений, я бы сделал это так:
Console println (
(
io.Source
fromFile "names.txt"
getLines ()
mkString ""
split ","
map (x => x.slice(1, x.length - 1))
sortBy (x => x)
zipWithIndex
)
map (t => (t._2 + 1) * (t._1 map (_.toChar - "A"(0).toChar + 1) sum) )
sum
)
Или, возможно, чтобы обойти методы без параметров, я бы сделал это:
Console println (
io.Source
.fromFile("names.txt")
.getLines
.mkString
.split(",")
.map(x => x.slice(1, x.length - 1))
.sortBy(x => x)
.zipWithIndex
.map(t => (t._2 + 1) * (t._1 map (_.toChar - "A"(0).toChar + 1) sum) )
.sum
)
Обратите внимание, что есть много места для комментариев, но, вообще говоря, что
делается, как правило, ясно. Люди, не привыкшие к этому, иногда могут потеряться
на полпути, без переменных, чтобы отслеживать значение / тип
преобразованное значение.
Теперь некоторые вещи, которые я бы сделал по-другому:
println ( // instead of Console println
Source // put import elsewhere
.fromFile("names.txt")
.mkString // Unless you want to get rid of /n, which is unnecessary here
.split(",")
.map(x => x.slice(1, x.length - 1))
.sorted // instead of sortBy
.zipWithIndex
.map { // use { only for multiple statements and, as in this case, pattern matching
case (c, index) => (index + 1) * (c map (_ - 'A' + 1) sum) // chars are chars
}
.sum
)
Я бы тоже не делал суммирование и умножение на одном шаге, поэтому:
.sorted
.map(_ map (_ - 'A' + 1) sum)
.zipWithIndex
.map { case (av, index) => av * (index + 1) }
.sum
Наконец, мне не очень нравится изменение размера строки, поэтому я мог бы вместо этого прибегнуть к регулярному выражению. Добавьте немного рефакторинга, и это то, что я, вероятно, напишу:
import scala.io.Source
def names = Source fromFile "names.txt" mkString
def wordExtractor = """"(.*?)"""".r
def words = for {
m <- wordExtractor findAllIn names matchData
} yield m group 1
def alphabeticValue(s: String) = s map (_ - 'A' + 1) sum
def wordsAV = words.toList.sorted map alphabeticValue
def multByIndex(t: (Int, Int)) = t match {
case (av, index) => av * (index + 1)
}
def wordsAVByIndex = wordsAV.zipWithIndex map multByIndex
println(wordsAVByIndex.sum)
EDIT
Следующим шагом будет переименование рефакторинга - выбор имен, которые лучше передают то, что делает каждая часть кода. Кен предложил в комментариях более подходящие имена, и я бы присвоил их еще одному варианту (он также показывает, насколько лучше наименование улучшает читабельность).
import scala.io.Source
def rawData = Source fromFile "names.txt" mkString
// I'd rather write "match" than "m" in the next snippet, but
// the former is a keyword in Scala, so "m" has become more
// common in my code than "i". Also, make the return type of
// getWordsOf clear, because iterators can be tricky.
// Returning a list, however, makes a much less cleaner
// definition.
def wordExtractor = """"(.*?)"""".r
def getWordsOf(input: String): Iterator[String] = for {
m <- wordExtractor findAllIn input matchData
} yield m group 1
def wordList = getWordsOf(rawData).toList
// I stole letterPosition from Kevin's solution. There, I said it. :-)
def letterPosition(c: Char) = c.toUpper - 'A' + 1 // .toUpper isn't necessary
def alphabeticValueOfWord(word: String) = word map letterPosition sum
def alphabeticValues = wordList.sorted map alphabeticValueOfWord
// I don't like multAVByIndex, but I haven't decided on a better
// option yet. I'm not very fond of declaring methods that return
// functions either, but I find that better than explicitly handling
// tuples (oh, for the day tuples/arguments are unified!).
def multAVByIndex = (alphabeticValue: Int, index: Int) =>
alphabeticValue * (index + 1)
def scores = alphabeticValues.zipWithIndex map multAVByIndex.tupled
println(scores sum)