Carbon
Carbon

Reputation: 3943

Scala - standard recursive pattern match on list

Given:

def readLines(x: String): List[String] = Source.fromFile(x).getLines.toList
def toKVMap(fName : String): Map[String,String] =
  readLines(fName).map(x => x.split(',')).map { case Array(x, y) => (x, y) }.toMap

I want to be able to take a string and a list of files of replacements and replace bracketed items. So if I have:

replLines("Hello",["cat"]) and cat contains ello,i!, I want to get back Hi!

I tried:

def replLines(inpQ : String, y : List[String]): String = y match { 
  case Nil => inpQ
  case x::xs => replLines(toKVMap(x).fold(inpQ) {
    case ((str: String), ((k: String), (v: String))) =>
      str.replace("[" + k + "]", v).toString
  }, xs)
}

I think the syntax is close, but not quite there. What have I done wrong?

Upvotes: 1

Views: 127

Answers (1)

Alex Savitsky
Alex Savitsky

Reputation: 2371

What you're looking for is most likely this (note the foldLeft[String] instead of fold:

def replLines(inpQ: String, y: List[String]): String = y match {
    case Nil => inpQ
    case x :: xs => replLines(toKVMap(x).foldLeft[String](inpQ) {
        case ((str: String), ((k: String), (v: String))) =>
            str.replace("[" + k + "]", v)
    }, xs)
}

fold generalizes the fold initial argument too much, and considers it a Serializable, not a String. foldLeft (and foldRight, if you prefer to start your replacements from the end) allows you to explicitly specify the type you fold on

EDIT: In fact, you don't even need a recursive pattern matching at all, as you can map your replacements directly to the list:

def replLines2(inpQ: String, y: List[String]): String =
  y.flatMap(toKVMap).foldLeft[String](inpQ) {
    case (str, (k, v)) => str.replace(s"[$k]", v)
  }

Upvotes: 2

Related Questions