ScalaのfoldLeft

Scala

今回は前に自分がなかなか読めなくて苦戦したScalaの機能、foldLeftについて書いてみたいと思う。

スポンサーリンク

foldLeftとは

foldLeftについて調べるとアキュームレータだの、再帰だの難しい話がたくさん出てきてイメージがつきにくいので、この記事ではイメージすることをメインに書きたいと思う。
Scalaでは以前の記事で書いたforeachのように、処理をループさせてリストを整形していくことが多々あるのだが、同じような仲間にfoldLeftというものがある。

リファレンスの定義にはこのように書いてある。

def foldLeft[B](z: B)(op: (B, A) ⇒ B): B

これだけみても訳がわからないが、この定義のポイントはカリー化された1つ目の引数と戻り値が同じBであるということ。

スポンサーリンク

Leftをfoldする

個人的にはholdLeftという関数名の方がしっくりくるのだが、左側(1つ目の引数)で渡されたものは保持したまま、2個目で渡された引数の処理(op: (B, A) ⇒ B)を要素分繰り返すイメージ。
以前の記事から神々の名前の入ったListを転用してサンプルを書いてみる。

val strArray = List("Anubis", "Isis", "Osiris", "Geb", "Atum")

いつも通り、この中から頭文字が”A”の名前だけ抜き出したいとする。
ただ今回は抜き出すだけではなく、頭文字がAの名前とそれ以外の名前を振り分けて新たにリストを作りたい。
そんなときにこのfoldLeftを使うことでサクッと処理ができる。

スポンサーリンク

foldLeftを利用してリストを作り直す

では実際にfoldLeftを使ってみる。

val (a_array, o_array) = strArray.foldLeft((List.empty[String], List.empty[String]))((x1, x2) => {
	x2.startsWith("A") match {
		case true => ((x1._1 :+ x2), x1._2)
		case _ => (x1._1, (x1._2 :+ x2))
	} 
})

カリー化された1つ目の引数には空のリストを2つtupleに格納し渡している。2つ目の引数にはラムダを渡している。
このラムダは引数に(x1, x2)を受け取り、前回の記事でも出てきたmatch-caseで処理を振り分けている。
で、このx1とx2には何が入ってくるのかという話だが、x1には1つ目の引数で渡されたtupleが入ってくる。そしてx2にはstrArrayの要素が順番に格納されてくる。
なので、その渡されてきた文字列の頭文字が”A”であるかの判定を行い、その結果がtrueだった場合はtupleの1つ目の要素に:+(add)し、2つ目の要素はそのまま返すという処理を行う。
それ以外の場合は、1つ目の要素はそのままに、2つ目の要素に:+を行い返す。
そして最終的な結果が(a_array, o_array)のtupleに格納される。
中身を確認するために出力のコードも加え、実行してみる。

val strArray = List("Anubis", "Isis", "Osiris", "Geb", "Atum")

val (a_array, o_array) = strArray.foldLeft((List.empty[String], List.empty[String]))((x1, x2) => {
	x2.startsWith("A") match {
		case true => ((x1._1 :+ x2), x1._2)
		case _ => (x1._1, (x1._2 :+ x2))
	} 
})

a_array.foreach(println)
println("--------------")
o_array.foreach(println)

実行結果は以下

username$ scala foldleft.scala 
Anubis
Atum
--------------
Isis
Osiris
Geb

こんな感じになる。

突然tupleとかも当たり前のようにミックスして来たが、今回は許してほしい。
チームでScalaを使うときが来たら補足するかもしれない。

コメント

タイトルとURLをコピーしました