[AD] Scalaアプリケーションの開発・保守は合同会社ミルクソフトにお任せください
Map
から条件に該当する要素を抽出して、それぞれに対して処理を適用した結果のコレクションを作成する方法をご紹介します。
以下のような、名前と金額のペアのMap
を例に考えてみましょう。
"apple"
と "orange"
を抽出して、さらに金額を円からドルに変換するには、どうすれば良いでしょうか?
val map = Map( "apple" -> 150, "banana" -> 210, "orange" -> 99, "strawberry" -> 110, "grape" -> 150, )
collectメソッドを使用する
collect
メソッドを使用することで、Map
から条件に該当する要素を抽出して、それぞれの要素に対して処理を適用した結果のコレクションを取得できます。
以下は、collect
メソッドを使用したサンプルです。
val result = map.collect: case (k, v) if (k == "apple" || k == "orange") => (k, v / 108.0) result.foreach { case (k, v) => val value = "%1$.2f".format(v) println(s"$k=$$ $value") }
実行結果は以下のようになります。
apple=$ 1.39 orange=$ 0.92
collect
メソッドに渡しているのは以下のような、Map
の要素のタプルを受け取り、タプルの第一要素が "apple"
または "orange"
の場合に、名前とドルがペアになったタプルを返す部分関数(PartialFunction
)です。
PartialFunction
とは、ある引数の場合は値を返しますが、値を返さない場合もある関数です。
前述のサンプルでcollect
メソッドに渡しているのは、以下のPartialFunction
です。
この関数は、 "apple"
または "orange"
の場合には名前とドルがペアになったタプルを返しますが、それ以外は値を返しません。
val func: PartialFunction[(String, Int), (String, Double)] = case (k, v) if(k == "apple" || k == "orange") => (k -> v / 108.0)
collectFirstメソッドを使用する
Map
内の要素から条件に該当する最初の要素に対して処理を適用した結果を取得するには、collectFirst
メソッドを使用します。
collectFirst
メソッドの戻り値はOption
です。
値がある場合はSome
、値がない場合はNone
を返します。
以下の例では、キーが "apple"
の要素の金額を、円からドルに変換しています。
val result = map.collectFirst: case ("apple", v) => v / 108.0 result match case Some(v) => println(s"$$ ${"%1$.2f".format(v)}") case None => println("Not Found.")
実行結果は、以下のとおりです。
$ 1.39
以下の例では、キーが"grapefruit"
の要素の金額を、円からドルに変換しています。
ところが、"grapefruit"
は存在しないため、collectFirst
メソッドはNone
を返します。
val result = map.collectFirst: case ("grapefruit", v) => v / 108.0 result match case Some(v) => println(s"$$ ${"%1$.2f".format(v)}") case None => println("Not Found.")
実行結果は、以下のとおりです。
Not Found.
mapメソッドとの違い
map
メソッドを使用すると、Map
の要素のそれぞれに対して処理を適用した結果のコレクションを作成できます。
map
メソッドはcollect
メソッドと違い、Map
内の要素を条件で選択することができません。
val result = map.map { case (k, v) => (k -> v / 108.0) } result.foreach { case (k, v) => println(s"${k}=$$ ${"%1$.2f".format(v)}") }
実行結果は、以下のとおりです。
orange=$ 0.92 apple=$ 1.39 strawberry=$ 1.02 banana=$ 1.94 grape=$ 1.39
filterメソッドとの違い
filter
メソッドを使用して、Map
から条件に該当する要素を抽出できます。
filter
メソッドはcollect
メソッドと違い、Map
の要素のそれぞれに対して処理を適用することができません。
val result = map.filter: case (k, v) => k == "apple" || k == "orange" result.foreach { case (k, v) => println(s"${k}=\\ ${"%d".format(v)}") }
実行結果は、以下のとおりです。
apple=150 orange=99
filterメソッドと、mapメソッドを使用する
最後にfilter
メソッドとmap
メソッドを使用して、collect
メソッドと同様に、Map
から条件に該当する要素を抽出して、それぞれに対して処理を適用した結果のコレクションを作成する方法をご紹介します。
以下のように、filter
メソッドで、Map
から条件に該当する要素を抽出した結果のMap
に対して、map
メソッドでそれぞれの要素に対して処理を適用します。
val result = map.filter { case (k, v) => k == "apple" || k == "orange" }.map: case (k, v) => (k -> v / 108.0) result.foreach { case (k, v) => println(s"${k}=$$ ${"%1$.2f".format(v)}") }
実行結果は、以下のとおりです。
apple=$ 1.39 orange=$ 0.92
ただし、この方法は、filter
メソッドでMap
を作成してから、map
メソッドでMap
を作成しており、処理効率が悪くなります。
そのため、collect
メソッド、collectFirst
メソッドの使用をおすすめします。