RosettaCodeData/Task/Levenshtein-distance/JavaScript/levenshtein-distance-2.js

110 lines
2.7 KiB
JavaScript
Raw Permalink Normal View History

2023-07-01 11:58:00 -04:00
(() => {
2024-07-13 15:19:22 -07:00
"use strict";
// ------------ LEVENSHTEIN EDIT DISTANCE ------------
2023-07-01 11:58:00 -04:00
// levenshtein :: String -> String -> Int
2024-07-13 15:19:22 -07:00
const levenshtein = sa =>
// The Levenshtein edit distance
// between two given strings.
sb => {
const cs = [...sa];
const go = (ns, c) => {
const calc = z => tpl => {
const [c1, x, y] = Array.from(tpl);
return Math.min(
1 + y,
1 + z,
x + (
c1 === c
? 0
: 1
)
);
};
const [n, ...ns1] = ns;
return scanl(calc)(1 + n)(
zip3(cs)(ns)(ns1)
);
2023-07-01 11:58:00 -04:00
};
2024-07-13 15:19:22 -07:00
return last(
[...sb].reduce(
go,
enumFromTo(0)(cs.length)
)
2023-07-01 11:58:00 -04:00
);
};
2024-07-13 15:19:22 -07:00
// ---------------------- TEST -----------------------
2023-07-01 11:58:00 -04:00
const main = () => [
["kitten", "sitting"],
["sitting", "kitten"],
["rosettacode", "raisethysword"],
["raisethysword", "rosettacode"]
].map(uncurry(levenshtein));
2024-07-13 15:19:22 -07:00
// ---------------- GENERIC FUNCTIONS ----------------
2023-07-01 11:58:00 -04:00
// enumFromTo :: Int -> Int -> [Int]
const enumFromTo = m =>
n => Array.from({
length: 1 + n - m
}, (_, i) => m + i);
// last :: [a] -> a
2024-07-13 15:19:22 -07:00
const last = xs => {
2023-07-01 11:58:00 -04:00
// The last item of a list.
2024-07-13 15:19:22 -07:00
const n = xs.length;
2023-07-01 11:58:00 -04:00
2024-07-13 15:19:22 -07:00
return 0 < n
? xs[n - 1]
: null;
};
2023-07-01 11:58:00 -04:00
// scanl :: (b -> a -> b) -> b -> [a] -> [b]
2024-07-13 15:19:22 -07:00
const scanl = f =>
// The series of interim values arising
// from a catamorphism. Parallel to foldl.
startValue => xs =>
xs.reduce(
(a, x) => {
const v = f(a[0])(x);
2023-07-01 11:58:00 -04:00
2024-07-13 15:19:22 -07:00
return [v, a[1].concat(v)];
}, [startValue, [startValue]]
)[1];
2023-07-01 11:58:00 -04:00
// uncurry :: (a -> b -> c) -> ((a, b) -> c)
const uncurry = f =>
// A function over a pair, derived
// from a curried function.
2024-07-13 15:19:22 -07:00
(...args) => {
2023-07-01 11:58:00 -04:00
const
2024-07-13 15:19:22 -07:00
[x, y] = Boolean(args.length % 2)
? args[0]
: args;
return f(x)(y);
2023-07-01 11:58:00 -04:00
};
// zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
const zip3 = xs =>
2024-07-13 15:19:22 -07:00
ys => zs => xs.slice(
0,
Math.min(...[xs, ys, zs].map(x => x.length))
)
.map((x, i) => [x, ys[i], zs[i]]);
2023-07-01 11:58:00 -04:00
// MAIN ---
2024-07-13 15:19:22 -07:00
return JSON.stringify(main());
2023-07-01 11:58:00 -04:00
})();