Hablando estrictamente a la forma de formato de ese código, sin hacer cambios estructurales, lo haría así:
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
)
O, tal vez, de moverse por los métodos sin parámetros, que había hacer esto:
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
)
Tenga en cuenta que hay un montón de espacio para comentarios, pero, en términos generales, lo que se está haciendo suele ser clara. Las personas que no están acostumbradas a ello pueden perderse a veces a la mitad, sin variables para realizar un seguimiento del significado/tipo del valor transformado .
Ahora, algunas cosas que haría de manera diferente son:
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
)
yo tampoco hago suma y la multiplicación en el mismo paso, por lo que:
.sorted
.map(_ map (_ - 'A' + 1) sum)
.zipWithIndex
.map { case (av, index) => av * (index + 1) }
.sum
Por último, I don' Es muy parecido al cambio de tamaño de la cuerda, así que podría recurrir a Regex en su lugar. Añadir un poco de refactorización, y esto es algo que probablemente escribiría:
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)
EDITAR
El siguiente paso sería una refactorización de cambio de nombre - la elección de nombres que mejor transmiten lo que cada parte del código está haciendo. Ken sugirió mejores nombres en los comentarios, y los apropiaría para una variante más (también muestra cuánto mejor nombrar a mejora la legibilidad).
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)
No tengo suficiente experiencia con Scala para darle buenos consejos, pero podría ser útil si dividiera cada 'mapa' en una línea diferente? Me interesa saber qué tienen que decir los Scala-it reales sobre esto. –
Una regla muy importante e independiente del lenguaje/paradigma no es hacer líneas de más de 80 caracteres (u otro valor razonable). 190 caracteres es una locura (y si tiene código de golf, al menos baje a 130 o ¡nunca le ganará a Perl!;)). – delnan
De acuerdo, es tan largo por razones pedagógicas. Pero mi pregunta es, en parte, sobre la mejor forma de dividirla en trozos más pequeños, aparte de elegir los descansos solo para que las líneas sean <80 caracteres. No estoy jugando al golf, pero estoy tratando de mejorar mi programación funcional ... –