如何使用更高级别的方法缩短以下代码段(toText
方法),例如map
,takeWhile
,filter
等:
/** Returns the text that is produced by this keypad from the given multi-tap input.
* For instance, the input `"33 3338881330000"` produces `"HIYAH!"`. The given string
* is assumed to consist of digits and spaces only.
*/
def toText(keysPressed: String): String = {
val pieces = keysPressed.split(" ")
var result = "" // gatherer
for (currentPiece <- pieces) { // most-recent holder
var remaining = currentPiece // gatherer
while (remaining.nonEmpty) {
val copyCount = countInitialCopies(remaining) // temporary
result += charFor(remaining(0), copyCount)
remaining = remaining.drop(copyCount)
}
}
result
}
其中:
/** Returns the character produced by pressing the given number key (from '0' to '9')
* the given number of times on this keypad. If a key is pressed more times than there
* are characters assigned to the key, the result "wraps around".
*/
def charFor(keyPressed: Char, timesPressed: Int): Char = {
val charactersForKeys = Vector(" .,!?", "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ", "ÅÄÖ")
val key = charactersForKeys(keyPressed.asDigit)
key((timesPressed-1) % key.length)
}
和
/** Determines the first letter of the given string, and returns the number of times
* the letter occurs consecutively at the beginning of the string. The given
* string must have at least one character.
*/
def countInitialCopies(str: String): Int = str.takeWhile(_ == str(0)).length
我尝试做以下事情,但它没有走得那么远:
def toText(keysPressed: String): String = keysPressed.split(" ").foldLeft("")(charFor(_(0), countInitialCopies(_)))
答案 0 :(得分:1)
不确定它是否真的更短但是这里有一个:
def toText(keysPressed: String): String = {
def split(seq: Seq[Char]): Stream[Seq[Char]] = {
if (seq.isEmpty)
Stream.empty
else {
val lr = seq.span(ch => ch == seq.head)
Stream.cons(lr._1, split(lr._2))
}
}
split(keysPressed)
.filter(s => s.head.isDigit) // filter out spaces between different series of the same digits
.map(s => charFor(s.head, s.length))
.mkString("")
}
此代码背后的理念是:
keysPressed
(被Seq[Char]
视为scala.collection.immutable.StringOps
视为隐含的Stream[Seq[Char]]
)分成countInitialCopies
,方式与cons
类似(请注意{ {1}}第二个参数是Seq
的其余部分的#34;递归&#34;(实际延迟)调用!)Seq[Char]
来自显式组分隔的空格,map
使用您的Stream[Seq[Char]]
charFor
Stream
的结果累积到String
答案 1 :(得分:1)
这是解决问题的方法略有不同。使用takeWhile()
但不多。
val charsForKeys = Vector(" .,!?", "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ")
def toText(keysPressed: String): String = {
if (keysPressed.isEmpty) ""
else {
val kpHead = keysPressed.head
val kpStr = keysPressed.takeWhile(_ == kpHead)
val kpLen = kpStr.length
if (kpHead.isDigit)
charsForKeys(kpHead.asDigit)(kpLen-1) + toText(keysPressed.drop(kpLen))
else
toText(keysPressed.drop(kpLen)) //not a digit, skip these chars
}
}
toText("33 3338881330000") //res0: String = HIYAH!
2,更短,尝试。使用foldRight()
和collect()
。
def toText(keysPressed: String): String = {
keysPressed.foldRight(List[String]()){
case (c, s::ss) => if (c == s.head) c+s :: ss
else c.toString :: s :: ss
case (c, Nil) => List(c.toString)
}.collect{
case s if s.head.isDigit => charsForKeys(s.head.asDigit)(s.length-1)
}.mkString
}