@antv/path-util
Version:
A common util collection for antv projects
117 lines (110 loc) • 2.98 kB
text/typescript
import { isEqual } from 'lodash-es';
export interface DiffType {
type: string;
min: number;
}
function getMinDiff(del: number, add: number, modify: number): DiffType {
let type = null;
let min = modify;
if (add < min) {
min = add;
type = 'add';
}
if (del < min) {
min = del;
type = 'del';
}
return {
type,
min,
};
}
/*
* https://en.wikipedia.org/wiki/Levenshtein_distance
* 计算两条path的编辑距离
*/
const levenshteinDistance = function (source: string, target: string): DiffType[][] {
const sourceLen = source.length;
const targetLen = target.length;
let sourceSegment, targetSegment;
let temp = 0;
if (sourceLen === 0 || targetLen === 0) {
return null;
}
const dist = [];
for (let i = 0; i <= sourceLen; i++) {
dist[i] = [];
dist[i][0] = { min: i };
}
for (let j = 0; j <= targetLen; j++) {
dist[0][j] = { min: j };
}
for (let i = 1; i <= sourceLen; i++) {
sourceSegment = source[i - 1];
for (let j = 1; j <= targetLen; j++) {
targetSegment = target[j - 1];
if (isEqual(sourceSegment, targetSegment)) {
temp = 0;
} else {
temp = 1;
}
const del = dist[i - 1][j].min + 1;
const add = dist[i][j - 1].min + 1;
const modify = dist[i - 1][j - 1].min + temp;
dist[i][j] = getMinDiff(del, add, modify);
}
}
return dist;
};
export default function fillPathByDiff(source: string, target: string) {
const diffMatrix = levenshteinDistance(source, target);
let sourceLen = source.length;
const targetLen = target.length;
const changes = [];
let index = 1;
let minPos = 1;
// 如果source和target不是完全不相等
// @ts-ignore
if (diffMatrix[sourceLen][targetLen] !== sourceLen) {
// 获取从source到target所需改动
for (let i = 1; i <= sourceLen; i++) {
let min = diffMatrix[i][i].min;
minPos = i;
for (let j = index; j <= targetLen; j++) {
if (diffMatrix[i][j].min < min) {
min = diffMatrix[i][j].min;
minPos = j;
}
}
index = minPos;
if (diffMatrix[i][index].type) {
changes.push({ index: i - 1, type: diffMatrix[i][index].type });
}
}
// 对source进行增删path
for (let i = changes.length - 1; i >= 0; i--) {
index = changes[i].index;
if (changes[i].type === 'add') {
// @ts-ignore
source.splice(index, 0, [].concat(source[index]));
} else {
// @ts-ignore
source.splice(index, 1);
}
}
}
// source尾部补齐
sourceLen = source.length;
if (sourceLen < targetLen) {
for (let i = 0; i < targetLen - sourceLen; i++) {
if (source[sourceLen - 1][0] === 'z' || source[sourceLen - 1][0] === 'Z') {
// @ts-ignore
source.splice(sourceLen - 2, 0, source[sourceLen - 2]);
} else {
// @ts-ignore
source.push(source[sourceLen - 1]);
}
}
}
return source;
}