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