Scalaを使ってみる: (4) Mapのメソッド
Scalaを勉強している.勉強中の身ではあるが,以下を例題として,Scalaプログラムの作り方について説明してみる.
テキストファイル中に現れる英単語の出現回数を数えて,出現回数の多い語から表示する.入力のテキストファイルとしては,Project Gutenberg 中のHalmet を用いる(ファイル名を hamlet.txt,改行はLFにした).
なお利用している環境は,Ubuntu 8.04 LTS上の Scala 2.8.0 RC2 (2010年5月10日リリース), Java 1.6.0である.
sizeメソッド
何種類の英単語があったかは,Map のキーを keys で取り出して, size で調べれば良い.
scala> words.keys.size
Int = 4906
単にMapに size を適用するのでも同じである.
scala> words.size
Int = 4906
filterメソッド
filterメソッドで一文字の英単語を数えてみると, 16種類あることがわかる.
scala> words.keys.filter(w => w.length() == 1).size Int = 16 scala> words.keys.filter(_.length() == 1).size Int = 16
なお,キーに対するfilterは filterKeys でも可能である.
scala> words.filterKeys(_.length() == 1).size Int = 16
Map に直接 filter を適用する場合は,キーと値の対を引数とする関数を与える.以下は,1回だけ出現している英単語の種類を数えている.
scala> words.filter(kv => kv._2 == 1).size Int = 2792 scala> words.filter(_._2 == 1).size Int = 2792
ここで kv._2 は対の第2要素,すなわち出現回数を取り出している.
あるいは case のパターンマッチを用いた無名関数を利用しても良い.ここで case のまわりは ( ) ではなく { } でくくられていることに注意.
scala> words.filter{case (w,c) => c == 1}.size Int = 2792
countメソッド
filter(f).size は count(f) と同一である.
scala> words.count{case (w,c) => c == 1} Int = 2792
reduceRightとreduceLeftメソッド
要素が x1, x2, x3, ..., xn の時, reduceRight(f) は f(x1, f(x2, ..., f(xn-1, xn))) を求める.また reduceLeft(f) は f(...f(f(x1, x2), x3), ..., xn) を求める.
たとえば,List(1,2,3).reduceRight(_-_) は, 1-(2-3) = 2 である.
scala> List(1,2,3).reduceRight(_-_) Int = 2
また,List(1,2,3).reduceLeft(_-_) は,(1-2)-3 = -4 である.
scala> List(1,2,3).reduceLeft(_-_) Int = -4
したがって,英単語の総数を求めるには,以下のようにすれば良い.
scala> words.values.reduceRight(_+_) Int = 34743 scala> words.values.reduceLeft(_+_) Int = 34743
一文字の英単語の総出現回数は,以下のようにすればわかる.
scala> words.filter(_._1.length == 1).values.reduceLeft(_+_) Int = 2062
直接的にsumメソッドを用いることもできる.
scala> words.filter(_._1.length == 1).values.sum Int = 2062
以下のようにすれば,最長の英単語が15文字だとわかる.
scala> words.map(_._1.length).reduceLeft(math.max(_,_)) Int = 15 scala> words.keys.filter(_.length == 15).toList List[String] = List(merchantability)
直接的にmaxメソッドを用いることもできる.
scala> words.map(_._1.length).max
Int = 15
foldRightとfoldLeftメソッド
要素が x1, x2, x3, ..., xn の時, foldRight(z)(f) は f(x1, f(x2, ..., f(xn, z))) を求める.また foldLeft(z)(f) は f(...f(f(z, x1), x2), ..., xn) を求める.
scala> List(1,2,3).foldRight("z")("("+ _ + _ + ")") java.lang.String = (1(2(3z))) scala> List(1,2,3).foldLeft("z")("("+ _ + _ + ")") java.lang.String = (((z1)2)3)
foldRightとfoldLeftの処理は,それぞれ /: と :\ でも実現できる.
scala> (List(1,2,3) :\ "z"){ "("+ _ + _ + ")" } java.lang.String = (1(2(3z))) scala> ("z" /: List(1,2,3)){ "("+ _ + _ + ")" } java.lang.String = (((z1)2)3)
以下は,toList と同様になる.
scala> words.keys.foldRight[List[String]](Nil)(_ :: _) List[String] = List(concernings, tristful, ...) scala> (words.keys :\ List[String]()) { _ :: _ } List[String] = List(concernings, tristful, ...)
compose, andThen, orElseメソッド
Mapはscala.Function1(一変数関数)の一種である.したがって compose(g) によって関数を合成できる.
たとえば,以下は文字列を英小文字に変換してから wordsを適用する関数 f1 を定義している.
scala> val f1 = words.compose[String](_.toLowerCase) f1: (String) => Int = <function1> scala> f1("Hamlet") Int = 118
一般に f = g compose h とすれば, f(x) = g(h(x)) となる関数fを定義できる.
一方 f = g andThen h とすれば, f(x) = h(g(x)) となる関数fを定義できる.
scala> val f2 = words andThen (- _) f2: PartialFunction[String,Int] = <function1> scala> f2("hamlet") Int = -118
また,Mapはscala.PartialFunction(部分関数)の一種である. words.isDefinedAt(w) で w に対する値が定義されているかどうかを調べることができる(words.contains(w)と同様).
scala> words.isDefinedAt("foo") Boolean = false scala> words.isDefinedAt("bar") Boolean = true
部分関数で値が定義されていない場合に,別の値を利用するには orElse を用いる.
以下は,words で定義されていない場合は, Map("foo" -> 1)を用いる部分関数 words2 を定義している.
scala> val words2 = words orElse Map("foo" -> 1) words2: PartialFunction[String,Int] = <function1> scala> words2("foo") Int = 1 scala> words2("bar") Int = 1
「Scalaを使ってみる」の目次
- (1) ファイルからの入力
- (2) 英単語の抽出
- (3) 出現回数を数える (mutable版)
- (4) Mapのメソッド
- (5) プログラム作成 (mutable版)
- (6) MultiSetを定義する (mutable版)
- (7) immutable MultiSetを定義する
- (8) immutable MultiSetのメソッドを定義する
- (9) immutable MultiSetのメソッドを高速化する
- (10) immutable MultiSetのメソッドを高速化する (続き)
- (11) immutable MultiSetのメソッドをリファクタリング
- (12) Martin Oderskyによるオンライン授業
- (13) Martin Oderskyによるオンライン授業 (第2回)