[AD] Scalaアプリケーションの開発・保守は合同会社ミルクソフトにお任せください
ScalaのMap
クラスのfind
メソッドの使い方について解説します。
後続の処理の内容によってはcollectFirst
メソッドを使用することができるので、その書き換え方についても紹介します。
find メソッドの使い方
find
メソッドは、特定の条件を満たす要素(キーや値)が存在する場合に、そのうちの一つを取得するメソッドです。
存在する場合にはSome(値)
、存在しない場合にはNone
を返します。
次のマップを例にfind
メソッドを使ってみましょう。
キーに数字、値にはフルーツの名前が小文字で入っています。
val map: Map[Int, String] = Map( 1 -> "apple", 2 -> "orange", 3 -> "grape", 4 -> "strawberry", )
このマップに含まれる要素のうち、
「キーが2で割り切れて、かつ、値に"g"という文字が含まれるもの」
のうちの最初の値を取得したい、という場合には、
find
メソッドを使用すれば期待する結果を得る事ができます。
map.find { case (k, v) => k % 2 == 0 && v.contains("g") } .foreach { case (_, v) => println(v) }
結果として"orange"を得ることができました。
orange
collectFirst メソッドによる書き換え方
さて、先程の処理に加えて、「取得した値を大文字に変換する」という処理をしたい場合を考えてみましょう。
find
メソッドを使用すると以下のように書くことができます。
map.find { case (k, v) => k % 2 == 0 && v.contains("g") } .map { case (_, v) => v.toUpperCase } .foreach(println)
結果はすべて大文字の"ORANGE"となります。
ORANGE
find
メソッドとmap
メソッドを使用する場合には、より簡潔に書き換えることができます。
ここで使用するのはcollectFirst
メソッドです。
collectFirst
メソッドは、条件に一致するものをひとつ抽出して、それに対して処理を行った結果を返すメソッドです。
実際にcollectFirst
メソッドで書き換えてみましょう。
map.collectFirst { case (k, v) if k % 2 == 0 && v.contains("g") => v.toUpperCase }.foreach(println)
結果も同じくすべて大文字の"ORANGE"が返ってきます。
ORANGE
使用上の注意
毎回同じ結果が返ってくるとは限らない
Map
クラスの各要素は順序が保証されていないので、
条件に合致する要素が複数存在した場合は、
find
メソッドの実行結果が変化する可能性があります。
これが気になる場合は、filter
メソッドで条件に一致するものを抽出した上で、
さらに追加の条件を指定して好ましい要素を取得するのが良いでしょう。
次の例では、条件に合うもののうち最もキーの大きい要素を取得してみます。
map.filter { case (_, v) => v.contains("g") } .toList .sortBy(_._1) // キーでソートする .reverse // 降順にする .headOption // 先頭の要素を取得 .foreach(e => println(e._2))
結果は以下のようになります。
"g"という文字を含む要素の中で最もキーの番号が大きいのはgrape
なので、
期待通りに取得できていることがわかります。
この場合はfind
メソッドを使わなくても取得できます。
grape
Scala 2.13以降ではより簡潔に書けるようになりました。
maxByOption
メソッドを使って以下のように書くことができます。
map.filter { case (_, v) => v.contains("g") } .maxByOption(_._1) .foreach(e => println(e._2))
grape