2011年11月9日水曜日

Scalaで文字列中の各出現文字をカウントする

Mapを使ったソースを書いてみようと思ってネタを考えてウダウダした結果、タイトルのようなソースが出来上がりました。
ついでなので関数の部分適用なども使ってみました。

下記サンプルソースに盛り込まれている要素は、
  • Map(mutable)
  • 関数の部分適用
  • 関数のオーバロード
になります。

では早速サンプルソースです。


object CharacterCount {     // scala.collection.mutableをインポートしておけば、mutable.Mapの宣言が短くできる     // インポート無 → cala.collection.mutable.Map[Char, Int]()     // インポート有 → mutableMap[Char, Int]()     import scala.collection.mutable
    /**      * 指定された文字列中に出現する各文字をカウントし、Mapに格納する      * @param text 出現する文字をカウントしたい文字列      * @param limit 出現回数がlimit回以上の文字のみ返す      * @return text中、limit回以上出現した文字と出現回数を格納したMap      */     def getMapWithLimit(text:String, limit:Int):mutable.Map[Char,Int] = {         count(text).filter( (kv) => kv._2 >= limit )     }     /**      * getMapWithLimitの部分適用      * getMapWithLimit(text, 1)と指定したのと同じ      * @param text 出現する文字をカウントしたい文字列      * @return text中、1回以上出現した文字と出現回数を格納したMap      */     def getMap = getMapWithLimit(_:String, 1)     /**      * 部分適用したgetMapをオーバロードしたもの      * getMapWithLimitと全く同じ      * @param text 出現する文字をカウントしたい文字列      * @param limit 出現回数がlimit回以上の文字のみ返す      * @return text中、limit回以上出現した文字と出現回数を格納したMap      */     def getMap(text:String, limit:Int):mutable.Map[Char,Int] = {         getMapWithLimit(text, limit)     }     /**      * 指定された文字列に出現する各文字をカウントし、Mapに格納して返す      * @param text 出現する文字をカウントしたい文字列      * @return text中の各文字と出現回数を格納したMap      */     private def count(text:String):mutable.Map[Char, Int] = {         val map = mutable.Map[Char, Int]()         text.foreach ( (char) => {             // MapのgetOrElseは、第1引数に指定したキーが存在しない場合に、第2引数の値を返します             val count = map.getOrElse( char, 0 )             map.update( char, count+1 )         })         map     }     // 関数の部分適用部分は、以下のようにしても結果は同じ     //def getMap(text:String) = { getMapWithLimit(text, 1) } }

getMap関数(メソッド?)を使うと、文字列中の各文字をキーとし、値に出現回数が格納されたmutable.Mapのインスタンスが返されます。
REPLから試すと以下のとおりです。


scala> val text = "となりのきゃくはよくかきくうきゃくだ。"
text: java.lang.String = となりのきゃくはよくかきくうきゃくだ。

// CharacterCountって打つのが面倒くさいのでccという変数に格納
scala> val cc = CharacterCount
cc: CharacterCount.type = CharacterCount$@2e5facbd

// 出現回数か1回以上の文字を取得(つまり全文字)
scala> cc.getMap(text)
res0: scala.collection.mutable.Map[Char,Int] = Map(の -> 1, か -> 1, う -> 1, く -> 4, ゃ -> 2, と -> 1, き -> 3, な -> 1, は -> 1, よ -> 1, 。 -> 1, り -> 1, だ -> 1)

// 出現回数が3回以上の文字のみ取得
scala> cc.getMap(text, 3)
res1: scala.collection.mutable.Map[Char,Int] = Map(く -> 4, き -> 3)


map.getOrElseに関して、これがScalaの目玉機能の一つであるOption型(Some型とNone型がある)に直結する機能です。JavaであればExceptionが発生しそうなところ、Noneが返されるので結果的に処理が無視される or 指定した処理が実行されることになります。 このOptionに関してはまだ勉強中なのでまた今度サンプルソースを書いてみたいと思っています。

これぐらいのプログラムであれば態々戻り値の型を書かなくても把握できるしScalaが理解できているならコメントもいらないくらいだと思います。(私は理解できていないのでコメントを書きました)
コメントと型の記述を省いて型推論に頼るとこんなにスッキリしました。


object CharacterCount2 {

    def getMapWithLimit(text:String, limit:Int) = {
        count(text).filter( (kv) => kv._2 >= limit )
    }

    def getMap = getMapWithLimit(_:String, 1)

    def getMap(text:String, limit:Int) = {
        getMapWithLimit(text, limit)
    }

    private def count(text:String) = {
        val map = scala.collection.mutable.Map[Char, Int]()
        text.foreach ( (char) => {
            map.update( char, map.getOrElse(char,0)+1 )
        })
        map
    }
}


今回は各文字でカウントアップしましたが、ちょっと工夫すれば単語単位でカウントすることも可能だと思います。
英語やドイツ語であればスペースで文章を区切ってしまえば自動的に単語単位になるので、うまいこと考えれば今年生まれた新語一覧なんかも作れるのかな~と思ったりしてます。

2011年11月3日木曜日

ドイツの歴史(超概要)


ドイツの歴史をざっくりまとめてみました。
本当にざっくりなので後々修正予定です。
しかし学生のころと違って興味を持って歴史を調べると楽しいですね~
なお、この超概要はこのサイト様を参考にさせていただいております。
参考というより、元々とても綺麗に整理されていたものをさらに私が理解できるレベルに箇条書きにした感じです。


1.ガリア遠征(BC58~BC51)などでゲルマン人は傭兵や農民としてローマ帝国に溶け込む


2.ゲルマン民族の大移動を経て、乱立した各地の王国をフランク王国が統一


3.843年のヴェルダン条約によって、分割されたうちの1つである東フランク王国(843年~962年)が現在のドイツの原型となった


4.東フランク王国の国王オットー1世は962年にアウグストゥス(古代ローマ帝国皇帝の称号)を得て、神聖ローマ帝国(962年~1806年)と呼ばれる緩やかな連合体を形成した(長い!)


5.中世におけるドイツには国家としての統一や民族意識はほとんどなく、各地に領邦国家が分立した。これが現在に続く連邦主義の基盤となっているといえる


6.宗教改革では、新旧両教に分かれて互いに争い、三十年戦争ではドイツ全土が徹底的に破壊され、1600万人いたドイツの人口が600万人に減少したといわれる


7.1701年に、北部の領邦君主ホーエンツォレルン家がプロイセン王国(1701年~1918年)を形成した


8.1806年まで神聖ローマ皇帝位を世襲していた「大ドイツ主義」派のハプスブルク家、「小ドイツ主義」派のホーエンツォレルン家とドイツ統一の役割を争った。


9.ナポレオンによる侵略を経て、民族意識と統一国家への志向を強め、19世紀前半にはプロイセンに主導的な役割を期待する気運が高まった。神聖ローマ帝国はナポレオンにの攻勢に屈して解体されハプスブルク家のフランツ2世が1806年に退位した。神聖ローマ帝国の滅亡である。


10.1871年、プロイセン国王ヴィルヘルム1世の戴冠によってドイツはドイツ系オーストリアを除く、小ドイツとしてのドイツ国(ドイツ帝国(1871年~1918年))として統一され、ベルリンを首都とした。(ちなみにこの戴冠式はパリのヴェルサイユ宮殿で行われた)


11.1918年、第1次世界大戦の敗北によって共和制(1919年~1933年)に移行。しかし、ヴァイマル共和制は小党乱立により政局は不安定で、第1次世界大戦後の賠償などもあり、ドイツ国内は驚異的なインフレとなる


12.1933年に、インフレなどを経て、アドルフ・ヒトラー率いるナチス党(国家社会主義ドイツ労働者党)が国民からの支持を受け、政権を握る


13.1939年9月に隣国ポーランドを攻略し、第2次世界大戦が勃発


14.第2次世界大戦に敗北し、オーデル・ナイセ線以東やシュレジェン地域を領土として喪失。さらに、アメリカ、イギリス、フランス、ソビエト連邦の四か国に分割統治される。


15.1949年、盆を暫定的な首都とするドイツ連邦共和国(西ドイツ)と、ベルリンの東部地区(東ベルリン)を首都とするドイツ民主共和国(東ドイツ)に分裂した。


16.1989年ソビエト連邦のペレストロイカに端を発した東ドイツの民主化運動(東欧革命)をきっかけにベルリンの壁が崩壊し、翌1990年に東西ドイツの再統一を果たし、首都を再びベルリンとした。


17.ボンからの連邦政府機関移転(実質的な首都機能移転)や東ベルリンを中心とするベルリンの再開発・インフラ整備を進め、2001年5月2日に、ベルリンへの首都機能移転が完了した。


18.現在ではヨーロッパで最大の国家の一つになる。しかし、東西分裂を原因とする東西の経済格差が影を落としている。
それでもなお、ドイツはフランスとともに欧州連合(EU)の中核国として発言力を増し続けている。
これを再びドイツが周辺国の脅威となると懸念している国もある。