fill-path-by-diff.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import { isEqual } from 'lodash-es';
  2. function getMinDiff(del, add, modify) {
  3. var type = null;
  4. var min = modify;
  5. if (add < min) {
  6. min = add;
  7. type = 'add';
  8. }
  9. if (del < min) {
  10. min = del;
  11. type = 'del';
  12. }
  13. return {
  14. type: type,
  15. min: min,
  16. };
  17. }
  18. /*
  19. * https://en.wikipedia.org/wiki/Levenshtein_distance
  20. * 计算两条path的编辑距离
  21. */
  22. var levenshteinDistance = function (source, target) {
  23. var sourceLen = source.length;
  24. var targetLen = target.length;
  25. var sourceSegment, targetSegment;
  26. var temp = 0;
  27. if (sourceLen === 0 || targetLen === 0) {
  28. return null;
  29. }
  30. var dist = [];
  31. for (var i = 0; i <= sourceLen; i++) {
  32. dist[i] = [];
  33. dist[i][0] = { min: i };
  34. }
  35. for (var j = 0; j <= targetLen; j++) {
  36. dist[0][j] = { min: j };
  37. }
  38. for (var i = 1; i <= sourceLen; i++) {
  39. sourceSegment = source[i - 1];
  40. for (var j = 1; j <= targetLen; j++) {
  41. targetSegment = target[j - 1];
  42. if (isEqual(sourceSegment, targetSegment)) {
  43. temp = 0;
  44. }
  45. else {
  46. temp = 1;
  47. }
  48. var del = dist[i - 1][j].min + 1;
  49. var add = dist[i][j - 1].min + 1;
  50. var modify = dist[i - 1][j - 1].min + temp;
  51. dist[i][j] = getMinDiff(del, add, modify);
  52. }
  53. }
  54. return dist;
  55. };
  56. export default function fillPathByDiff(source, target) {
  57. var diffMatrix = levenshteinDistance(source, target);
  58. var sourceLen = source.length;
  59. var targetLen = target.length;
  60. var changes = [];
  61. var index = 1;
  62. var minPos = 1;
  63. // 如果source和target不是完全不相等
  64. // @ts-ignore
  65. if (diffMatrix[sourceLen][targetLen] !== sourceLen) {
  66. // 获取从source到target所需改动
  67. for (var i = 1; i <= sourceLen; i++) {
  68. var min = diffMatrix[i][i].min;
  69. minPos = i;
  70. for (var j = index; j <= targetLen; j++) {
  71. if (diffMatrix[i][j].min < min) {
  72. min = diffMatrix[i][j].min;
  73. minPos = j;
  74. }
  75. }
  76. index = minPos;
  77. if (diffMatrix[i][index].type) {
  78. changes.push({ index: i - 1, type: diffMatrix[i][index].type });
  79. }
  80. }
  81. // 对source进行增删path
  82. for (var i = changes.length - 1; i >= 0; i--) {
  83. index = changes[i].index;
  84. if (changes[i].type === 'add') {
  85. // @ts-ignore
  86. source.splice(index, 0, [].concat(source[index]));
  87. }
  88. else {
  89. // @ts-ignore
  90. source.splice(index, 1);
  91. }
  92. }
  93. }
  94. // source尾部补齐
  95. sourceLen = source.length;
  96. if (sourceLen < targetLen) {
  97. for (var i = 0; i < targetLen - sourceLen; i++) {
  98. if (source[sourceLen - 1][0] === 'z' || source[sourceLen - 1][0] === 'Z') {
  99. // @ts-ignore
  100. source.splice(sourceLen - 2, 0, source[sourceLen - 2]);
  101. }
  102. else {
  103. // @ts-ignore
  104. source.push(source[sourceLen - 1]);
  105. }
  106. }
  107. }
  108. return source;
  109. }
  110. //# sourceMappingURL=fill-path-by-diff.js.map