Scalaで全角数字を半角数字に変換。その再帰、たたみ込める?
全角数字を半角数字に置き換えるというよくある処理。
再帰関数を自分で定義して書くなら、次のようになります。
def fullWidthNumberToHalfWidthNumber(str: String): String = { val fullWidthNumbers = List("0", "1", "2", "3", "4", "5", "6", "7", "8", "9") @scala.annotation.tailrec def convert(str: String, acc: Int): String = if (acc > 9) str else convert(str.replaceAll(fullWidthNumbers(acc), acc.toString), acc + 1) convert(str, 0) }
再帰関数を定義している分、冗長になるためもう少し、シンプルに記述したいところです。
そこで、foldLeft
を使って、これを書き直すと下記のように記述できます。
def fullWidthNumberToHalfWidthNumber(str: String): String = { val fullWidthNumbers = List("0", "1", "2", "3", "4", "5", "6", "7", "8", "9") fullWidthNumbers.zipWithIndex.foldLeft(str){ case (x, (c, i)) => x.replaceAll(c, i.toString) } }
一度、fullWidthNumbers.zipIndex
とすることで、List(("1", 1), ("2", 2), ...)
のようなインデックス付きのリストを作っています。
また、foldLeft
に渡す関数の引数についても{ case (x, (c, i)) => }
このような省略をできるのもScalaの便利なところ。
省略をしなければ次のような意味を持ちます。これを、case
から書き始められるのは非常に便利です。
(str, tuple) => (str, tuple) match { case (x, (c, i)) => // ... }
再帰関数を定義しようとするときは、いったんfoldLeft
などたたみ込み関数で代用出来ないか考えてみると、よいかもしれません。