LoginSignup
14
15

More than 5 years have passed since last update.

[プログラミング作法]マルコフ連鎖アルゴリズムをrubyで実装してみた

Last updated at Posted at 2014-05-05

最近「プログラミング作法」という本を読んでいます。基本C言語ベースで話が進んでいくんですが、アルゴリズム自体は言語問わず勉強になると思いましたので、rubyで「マルコフ連鎖アルゴリズム」を実装してみました。きっともっといいアルゴリズムがあるはずなので、教えてください(他力本願)

markov.rb
# 番兵(NONWORD)を定義
NONWORD = "\n"

# 標準入力から文章を取得。先頭と末尾に番兵を配置し
# 後処理を単純化
text = [NONWORD, NONWORD] +  STDIN.read.split + [NONWORD]

# == 入力フェーズ
# プレフィクスをキーとし、サフィックスをバリューとするハッシュ配列を作成
# text内の連続する2ワードがプレフィックス。それに続く1ワードがサフィックス
# となるのでtextを3つずつに分割してeachで回す。
h = {}
text.each_cons(3).each do |pre_suf|
  suffix = pre_suf.pop
  prefix = pre_suf
  h[prefix] ||= []
  h[prefix] << suffix
end

# == 出力フェーズ
# 初期値をNONWORDに設定し、それをキーとしてランダムにサフィックスを表示する。
# プレフィクスの先頭を削除、表示したサフィックスを末尾に追加、次のキーとする。
# 上記をサフィックスにNONWORDがくるまで繰り返す。
prefix = [NONWORD, NONWORD]
loop do
  break if h[prefix].last == NONWORD

  suffix = h[prefix][rand(h[prefix].size)]

  print("#{suffix} ")

  prefix.delete_at(0)
  prefix << suffix
end
puts

追記

入力フェーズでサフィックスを+=を使って代入していましたが、<<を使うことで高速化することができたので、修正しました。
本書記載のperlスクリプトとの速度比較で約8倍の差があったので、何かおかしいんだろうと思い調べていたところ、こちらの記事を見つけました。+=は内部処理の関係で配列のインスタンスを再生成するようです。<<に変更したところ、perlスクリプトと同等の速度になりました。

14
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
15