levenshtein_distance_alignment.sf 1.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. #!/usr/bin/ruby
  2. #
  3. ## https://rosettacode.org/wiki/Levenshtein_distance/Alignment
  4. #
  5. func align(s, t) {
  6. s.chars!.prepend!('^')
  7. t.chars!.prepend!('^')
  8. var A = []
  9. {|i| A[i][0]{@|<d s t>} = (i, s.slice(1, i).join, '~' * i) } << ^s
  10. {|i| A[0][i]{@|<d s t>} = (i, '-' * i, t.slice(1, i).join) } << ^t
  11. for i (1 .. s.end) {
  12. for j (1 .. t.end) {
  13. if (s[i] != t[j]) {
  14. A[i][j]{:d} = 1+(
  15. var min = Math.min(A[i-1][j]{:d}, A[i][j-1]{:d}, A[i-1][j-1]{:d})
  16. )
  17. A[i][j]{@|<s t>} = (A[i-1][j]{:d} == min
  18. ? [A[i-1][j]{:s}+s[i], A[i-1][j]{:t}+'-']
  19. : (A[i][j-1]{:d} == min
  20. ? [A[i][j-1]{:s}+'-', A[i][j-1]{:t}+t[j]]
  21. : [A[i-1][j-1]{:s}+s[i], A[i-1][j-1]{:t}+t[j]]))...
  22. }
  23. else {
  24. A[i][j]{@|<d s t>} = (
  25. A[i-1][j-1]{:d},
  26. A[i-1][j-1]{:s}+s[i],
  27. A[i-1][j-1]{:t}+t[j],
  28. )
  29. }
  30. }
  31. }
  32. return [A[-1][-1]{@|<s t>}]
  33. }
  34. say (var r = align("rosettacode", "raisethysword"))
  35. assert_eq(r, ['ro-settac-o-de', 'raisethysword-'])