Home Diary 倉庫

2004年04月27日

2004年04月27日

課題2


ファイルがどれだけ似ているか
LCSのアルゴリズムを用いて,2つのファイルの類似度を調べる.

    * 指定された2つのファイルの内容をトークンに分解する.
          o トークンへの分解はStreamTokenizerのデフォルトでよい. (分解仕方を工夫してもよいが,要求はしない.) 
    * そのようにしてできた2つのトークンのリストのLCSの「対応」を計算する.
          o LCSの長さだけでなく,LCSそのものを具体的に求める.
          o LCSは複数ある場合もあるが,一つ求めればよい.
          o LCSの「対応」とは,
                + LCS = xi1 xi2 ... xim,
                + LCS = yj1 yj2 ... yjm,としたとき,
                + リスト( (i1, j1), (i2,j2), ... , (im,jm) ) のこと. 
            「対応」が複数ある場合もあるが,一つ求めればよい. 
    * オプション(A)
          o LCSの「対応」をグラフィックス表示する. 

某課題。longest common sequence(とかいうもの)のひとつを求める。単位はtoken。


module Main where
import Array

lcstable :: [String] -> [String] -> Array (Int,Int) Int
lcstable x y = a where
	       a = array ((0,0),(lenx,leny))
		   [((i,j), (lcslen i j)) | i <- [0..(lenx)], j<-[0..(leny)]]
		       where
		       lenx = length x
		       leny = length y
		       lcslen 0 _ = 0
		       lcslen _ 0 = 0
		       lcslen i j = if (x!!(i-1) == y!!(j-1))
				    then 1+a!(i-1,j-1)
				    else max (a!(i,j-1)) (a!(i-1,j))

lcsmatch :: [String] -> [String] -> [(Int,Int)]
lcsmatch [] _ = []
lcsmatch _ [] = []
lcsmatch x y  = if (last x) == (last y)
		then (lcsmatch (heads x) (heads y))++[(lenx,leny)]
		else if l!(lenx-1,leny)==l!(lenx,leny)
		     then lcsmatch (heads x) y
		     else lcsmatch x (heads y)
			 where
			 lenx = length x
			 leny = length y
			 heads x = take ((length x)-1) x
			 l = lcstable x y

a1 :: [String]
a1 = ["a","b","d","f","g","h","j","m","p","s",""]
a2 :: [String]
a2 = ["b","c","d","e","f","g","p","q","r","s",""]

main = do
       putStr (show (lcsmatch a1 a2))


Main> main
[(2,1),(3,3),(4,5),(5,6),(9,7),(10,10),(11,11)]

直感的に記述ができる、気がする。hugsってmain module内のmain関数呼んでくれるようなコマンドラインオプションとかないのかなぁ...