ふとレーベンシュタイン距離 (編集距離) の計算を書きたくなったので書いてみた。わりと綺麗に書けたと思った。
def levenshtein_distance(s, t) t.chars.with_index.inject(0..s.size) do |r, (a, z)| z += 1 [z] + s.chars.zip(r.each_cons(2)).map do |b, (x, y)| z = [y + 1, z + 1, x + (a == b ? 0 : 1)].min end end.last end p levenshtein_distance("kitten", "sitting") #=> 3 p levenshtein_distance("Saturday", "Sunday") #=> 3
んー、でも、with_index が 0 origin 固定なのがいまいちですね。あと scanl や mapAccumL が欲しい、かなあ。
やはり Haskell はいい感じ。もっと綺麗に短く書けるかな?
levenshtein_distance :: Eq a => [a] -> [a] -> Int levenshtein_distance s t = last $ foldl f [0..length s] $ zip t [1..] where f r (a, z) = scanl (g a) z $ zip3 s r (tail r) g a z (b, x, y) = minimum [y + 1, z + 1, x + fromEnum (a /= b)] main :: IO () main = do print $ levenshtein_distance "kitten" "sitting" -- 3 print $ levenshtein_distance "Saturday" "Sunday" -- 3