Mapの値を取得するには?

Scala 3 (Dotty 0.26.0-RC1) 2.13.3 2.12.12
最終更新:2020年7月6日

[AD] scalapediaでは記事作成ボランティアを募集しています

この記事では getgetOrElseapplyapplyOrElse メソッドの使い方、使い分けについて解説します。

使い分け早わかり!

getgetOrElseapplyapplyOrElse の使い分けについては、 以下の問いに答えていけば自ずと導かれます。

早速、それぞれのメソッドの使い方について見ていきましょう。

get メソッドの使い方

以下のマップについて見てみます。

case class Person(firstName: String, lastName: String, age: Int) val people: Map[Int, Person] = Map( 1 -> Person("Andrea", "Thompson", 23), 2 -> Person("Austin", "May", 17), 3 -> Person("John", "Winston", 18), 4 -> Person("Christina", "Chandler", 20), 5 -> Person("John", "Thompson", 23) )

get はいちばん基本のメソッドです。
戻り値がOptionなので、値がある場合とない場合のそれぞれに対応することができます。
値がある場合には、以下のように Some に包まれた値を得ることができます。

println( people.get(1) )
Some(Person(Andrea,Thompson,23))

値がない場合についても見てみましょう。
値がない場合には None が返ってくるので、安全に処理することができます。

println( people.get(100) )
None

getOrElse メソッドの使い方

値がない場合の値が既に決まっている場合には、 getOrElse を使用することができます。

キーに対応する値があれば、その値がそのまま返ってきます。

println( people.getOrElse(1, "NO NAME") )
Person(Andrea,Thompson,23)

値がない場合には、デフォルト値が返ってきます。

println( people.getOrElse(100, "NO NAME") )
NO NAME

計算量節約のためのメモ

getOrElse の第2引数に渡すデフォルト値は、名前渡しになっています。
名前渡しになっているということは、このデフォルト値は「なかった場合」のみ、その都度評価されるということです。
したがって計算済みの値を渡すべきなのか、未評価のまま関数として渡すべきなのか、検討の余地があります。

applyOrElse メソッドの使い方

使い方は getOrElse と同じです。
getOrElse との使い分け方としては、無かった場合の処理として 「第一引数に渡した値を取るfunction1〜functionN」を渡す場合には、applyOrElse を使います。

具体的に見てみましょう。
次の関数を定義します。
キーを渡すとキーを含んだエラーメッセージをを返してくれる関数です。

def errorMessage(id: Int): String = s"NO NAME; id=$id"

applyOrElse に第2引数に先程定義した関数を渡してみましょう。
引数リストを省略することでFunction1として渡すことができます。
値がある場合には期待通りの値を出力します。

println( people.applyOrElse(1, errorMessage) )
Person(Andrea,Thompson,23)

ない場合についても見てみましょう。
期待通り、エラーメッセージが出力されています。

println( people.applyOrElse(100, errorMessage) )
NO NAME; id=100

備考

applyOrElsepartialFunction のメソッドです。
したがってMapに限らず、partialFunctionを継承しているクラス、例えば ListSet でも使うことができます。

apply メソッドの使い方

「いやいや apply には値の存在するキーしか渡さないので大丈夫です」と断言できる場合には apply メソッドを使うことができます。
apply は省略できるので、以下のようにスッキリ書くことができます。
戻り値も期待通り。

println( people(1) )
Person(Andrea,Thompson,23)

ただし、そう言いつつも実際にはキーがありませんでした、となると盛大に例外が飛びます。
残念でしたでは済みませんので、細心の注意を払ってください。

println( people(100) )

たとえば、もし仕様変更で予期せぬ値が渡ってきた場合には…?
ほら、言わんこっちゃないですね。

java.util.NoSuchElementException at scala.collection.immutable.BitmapIndexedMapNode.apply(HashMap.scala:608) at scala.collection.immutable.HashMap.apply(HashMap.scala:131) ... 36 elided

「仕様変更により値のないキーが渡ってくるようになる」ような可能性が後々まで絶対無いですとも言い切れない場合には、 apply はできるだけ使わないようにして、get などを使うことをおすすめします。

まとめ

まずは get を使いましょう。
デフォルト値を扱いたい場合はその内容に応じて getOrElseapplyOrElse を使い分けましょう。
そして、apply のことはなるべく忘れましょう。

あらためて順を追って述べると、以下のようになります。

  1. キーに対応する値が絶対に存在するとは言い切れない場合は、getgetOrElseapplyOrElse のいずれかを使います。
  2. 値が無いからといってデフォルトで返したい値が特に無い場合はget を使います。
  3. 値が無いときのデフォルト値/処理がある場合は、 getOrElse または applyOrElse を使います。
  4. デフォルト値/処理が「このメソッドに渡した値(つまりキー)をとる関数の実行結果」である場合は applyOrElse を使います。
  5. そうではない場合、つまりデフォルト値が定数であったり、キーとは関連がない処理の場合には getOrElse を使用します。
  6. そして、「キーに対応する値は絶対に存在する。間違いない」と自信を持って断言できる場合には apply を使っても良いでしょう。

以上です。
手に使い分けていきましょう。

サイト内検索