2017-12-01 5 views
0

Wie kann ich das folgende Stück Code (die toText-Methode) mit einem höheren Ebene Methoden wie map verkürzen, takeWhile, filter, etc .:Scala - Stück Code mit höherer Ebene Methoden Verkürzung

/** 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 
} 

wo:

/** 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) 
} 

und:

/** 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 

Ich habe versucht, die folgenden zu tun, aber es ging nicht so weit:

def toText(keysPressed: String): String = keysPressed.split(" ").foldLeft("")(charFor(_(0), countInitialCopies(_))) 

Antwort

1

Hier ist eine etwas andere App Plötzlich auf das Problem. Verwendet takeWhile() aber nicht viel anderes.

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! 

zweiter, kürzerer, Versuch. Verwendet foldRight() und 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 
} 
+0

Wie unterscheidet sich dieser Code vom Original, außer dass beide Methoden inliniert sind? Ist der Unterschied in einem anderen Ansatz, um Räume zu behandeln? Oder ist es Rekursion statt Schleifen? – SergGr

+0

@SergGr; Ja, Rekursion, unveränderliche Variablen .... Ich sagte, es sei "etwas anders". – jwvh

1

Nicht sicher, ob es wirklich kürzer ist, aber hier ist eine:

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("") 
} 

Die Idee dahinter Code:

  1. erste geteilten die keysPressed (behandelt als Seq[Char] dank impliziten scala.collection.immutable.StringOps) in a Stream[Seq[Char]] in ähnlicher Weise wie Ihre countInitialCopies (beachten Sie, dass cons Sekunden Argument ein „rekursiv“ ist (tatsächlich verzögert) Anruf auf dem Rest des Seq!)
  2. dann Seq[Char] herauszufiltern, die von Räumen für explizite Gruppen Trennung kommen,
  3. dann map, die gefiltert Stream[Seq[Char]] Ihre charFor
  4. mit
  5. akkumulieren schließlich das Ergebnis von Stream in eine String