Scala の Seq に定義されているメソッドを試すシリーズ(目次)。 今回は既にある Seq オブジェクトから新たに Seq オブジェクトを作るメソッド。 特に生成された Seq オブジェクトの要素数が元の Seq オブジェクトの要素数と一致するものを試していきます。 加えて、関数や部分関数 (PartialFunction) を返すメソッドも試します。
今回扱うメソッド
まずは、要素数の等しい新たな Seq オブジェクトを生成するメソッド。def map[B](f: (A) ⇒ B): Seq[B] def updated(index: Int, elem: A): Seq[A] def reverse: Seq[A] def reverseMap[B](f: (A) ⇒ B): Seq[B] def sorted[B >: A](implicit ord: math.Ordering[B]): Seq[A] def sortWith(lt: (A, A) ⇒ Boolean): Seq[A] def sortBy[B](f: (A) ⇒ B)(implicit ord: math.Ordering[B]): Seq[A]
加えて、関数や部分関数を返すメソッド。 これらは PartialFunction トレイトから継承しているメソッドです。
def lift: (Int) ⇒ Option[A] def orElse[A1 <: Int, B1 >: A](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] def compose[A](g: (A) ⇒ Int): (A) ⇒ A def andThen[C](k: (A) ⇒ C): PartialFunction[Int, C]
サンプルコード(要素数が同じ Seq オブジェクトを返すメソッド)
まずは要素数が同じ Seq オブジェクトを返すメソッド。 scala.collection.Seq の apply ファクトリ・メソッドで返される実装ではイミュータブルな Seq が返されるので、ここで扱うメソッドは元の Seq を変更しません。map メソッド
map メソッドは、元の Seq の要素型を引数にとる関数を引数にとり、各要素にその関数を適用した結果を要素とする新たな Seq を生成します。val seq = Seq("zero", "one", "two", "three", "four") // map メソッド assert( seq.map(_.length) == Seq(4, 3, 3, 5, 4) ) // 各文字列をその長さの Int 値に変換
map メソッドは filter, flatMap メソッドと共にモナド関連の話でも出てくる重要なメソッドですね。
updated メソッド
updated メソッドは、インデックスをしてしてその位置の要素を変更するメソッドです。 正確には指定した位置の要素を変更した Seq を返します。 Java のコレクションいう set メソッドですね。val seq = Seq("zero", "one", "two", "three", "four") // updated メソッド assert( seq.updated(2, "二") == Seq("zero", "one", "二", "three", "four") )
reverse メソッド
reverse メソッドは、要素の順序を反転した Seq オブジェクトを返します。val seq = Seq("zero", "one", "two", "three", "four") // reverse メソッド assert( seq.reverse == Seq("four", "three", "two", "one", "zero") )
reverseMap メソッド
reverseMap メソッドは、map メソッドと reverse メソッドを合わせたメソッドです。 実装クラス(LinearSeq とかかな)によってはパフォーマンスがいいんだと思います。val seq = Seq("zero", "one", "two", "three", "four") // reverseMap メソッド assert( seq.reverseMap(_.length) == Seq(4, 5, 3, 3, 4) )
sorted メソッド
sorted メソッドは、要素を昇順に並べます。 順序を指定しなければ自然な順序*1が使われます。 String オブジェクトに対しては辞書順序が使われます。val seq = Seq("zero", "one", "two", "three", "four") // sorted メソッド assert( seq.sorted == Seq("four", "one", "three", "two", "zero") )
独自の順序を使いたい場合は Ordering オブジェクトを作って引数として渡します。
val lenOrd: Ordering[String] = (x, y) => x.length - y.length // 文字列長が短い順 assert( seq.sorted(lenOrd) == Seq("one", "two", "zero", "four", "three") )
sortWith メソッド
sortWith メソッドは、sorted メソッドに Ordering オブジェクトを渡す場合のように独自の順序で要素を並び替えます。 ただし、順序の指定としては Ordering オブジェクトではなく (A, A) => Boolean 型の関数(A は要素の型)を渡します。val seq = Seq("zero", "one", "two", "three", "four") // sortWith メソッド assert( seq.sortWith((x, y) => x.length < y.length) == // 文字列長が短い順 Seq("one", "two", "zero", "four", "three") )
順序を定義する関数は、第1引数の方が小さい場合には true を、第2引数が小さい場合には false を返すように定義します。
sortBy メソッド
sortBy メソッドは、要素を別の型に変換して、その変換後のオブジェクトの自然な順序で並べ替えます。 返される Seq オブジェクトの要素は元の要素です(変換後の要素ではない)。val seq = Seq("zero", "one", "two", "three", "four") // sortBy メソッド assert( seq.sortBy(_.length) == Seq("one", "two", "zero", "four", "three") ) // 文字列長で小さい順に並べる
サンプルコード(関数・部分関数を返すメソッド)
以下のメソッドは、PartialFunction トレイトに定義されているメソッドです。 どれも返り値は Seq ではなく関数もしくは部分関数 (PartialFunction) です。lift メソッド
lift メソッドは、インデックスを指定するとその位置の要素を返すが、対応する要素がないときに例外が投げられないように Option Option で包んで返す関数を返します。// lift メソッド val lifted = seq.lift lifted(1) match { case Some(s) => println("[lift] " + s) case None => println("[lift]error!") } // 「[lift] one」と表示される
orElse メソッド
orElse メソッドは、引数に別の部分関数をとり、返り値として部分関数を返します。 この返り値の部分関数は、インデックスに対応する Int 値を引数にとる apply メソッドを持ち、元の Seq オブジェクトがこのインデックスに対応する要素を持てばそれを返し、対応する要素がなければ orElse メソッドに渡された部分関数にインデックスの Int 値を渡してその結果を返します。以下では、Seq が部分関数、つまり PartialFunction トレイトを継承していることを利用して、orElse の引数にも Seq を使っています。
val seq1 = Seq("zero", "one", "two", "three", "four") val seq2 = Seq("0", "1", "2", "3", "4", "5", "6", "7") // orElse メソッド val oe1 = seq1 orElse seq2 assert( oe1(0) == "zero" ) // seq1 より assert( oe1(4) == "four" ) // seq1 より assert( oe1(5) == "5" ) // seq2 より assert( oe1(7) == "7" ) // seq2 より // 逆に呼び出すと結果も異なる val oe2 = seq2 orElse seq1 assert( oe2(0) == "0" ) // seq2 より
当然のことながら、orElse メソッドのレシーバと引数を逆にすると挙動が変わります。
compose メソッド
compose メソッドは数学的な関数の合成です。 関数 (f compose g)(x) は数学の関数の記法として f(g(x)) と同じです。val f = Seq("zero", "one", "two", "three") val g = Map("Alice" -> 0, "Bob" -> 1, "Eve" -> 2) // compose メソッド val fg = f compose g assert( fg("Alice") == "zero" ) assert( fg("Bob") == "one" ) assert( fg("Eve") == "two" ) assert( fg("Alice") == f(g("Alice")) ) // (f compse g)(x) は f(g(x)) と同じ
andThen メソッド
andThen メソッドは compose メソッドと逆の合成をします。val f = Seq("zero", "one", "two", "three") val g: String => Char = _.charAt(0) // 文字列の最初の1文字を返す // andThen メソッド val gf = f andThen g // compose メソッドの逆 assert( gf(0) == 'z' ) assert( gf(1) == 'o' ) assert( gf(2) == 't' ) assert( gf(0) == g(f(0)) ) // (f andThen g)(x) は g(f(x)) と同じ
今回は以上です。
次回は元の Seq オブジェクトと要素数が異なる Seq オブジェクトを生成するメソッドを試す予定。
- 作者: Martin Odersky,Lex Spoon,Bill Venners,羽生田栄一,水島宏太,長尾高弘
- 出版社/メーカー: インプレス
- 発売日: 2016/09/20
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る