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関数呼んでくれるようなコマンドラインオプションとかないのかなぁ...