Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/src/resources/tools/ast-tracing/edit-distance.ts
12922 views
1
type Result = {
2
type: "insert" | "delete" | "replace" | "begin";
3
location: [number, number];
4
newLocation: [number, number];
5
};
6
7
export const editDistance = (a: string[], b: string[]): Result[] => {
8
type Edit = {
9
type: "insert" | "delete" | "replace" | "begin";
10
cost: number;
11
};
12
const result: Result[] = [];
13
14
const dp: (Edit | undefined)[][] = [];
15
for (let i = 0; i <= a.length; i++) {
16
dp.push([]);
17
for (let j = 0; j <= b.length; j++) {
18
dp[i].push(undefined);
19
}
20
}
21
dp[0][0] = { type: "begin", cost: 0 };
22
for (let i = 1; i <= a.length; i++) {
23
dp[i][0] = { type: "delete", cost: i };
24
}
25
for (let j = 1; j <= b.length; j++) {
26
dp[0][j] = { type: "insert", cost: j };
27
}
28
for (let i = 1; i <= a.length; i++) {
29
for (let j = 1; j <= b.length; j++) {
30
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
31
32
const ops: Edit[] = [
33
{ type: "delete", cost: dp[i - 1][j]!.cost + 1 },
34
{ type: "insert", cost: dp[i][j - 1]!.cost + 1 },
35
{
36
type: "replace",
37
cost: dp[i - 1][j - 1]!.cost + cost,
38
},
39
];
40
ops.sort((a, b) => a.cost - b.cost);
41
dp[i][j] = ops[0];
42
}
43
}
44
// build results array
45
let i = a.length;
46
let j = b.length;
47
while (i > 0 || j > 0) {
48
const op = dp[i][j]!;
49
const newLocation: [number, number] = [i, j];
50
switch (op.type) {
51
case "begin":
52
throw new Error("should not happen");
53
case "delete":
54
i--;
55
break;
56
case "insert":
57
j--;
58
break;
59
case "replace":
60
i--;
61
j--;
62
break;
63
}
64
result.push({ type: op.type, location: [i, j], newLocation });
65
}
66
result.reverse();
67
return result;
68
};
69
70