arrayRemoveDuplicates.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import Check from "./Check.js";
  2. import defaultValue from "./defaultValue.js";
  3. import defined from "./defined.js";
  4. import CesiumMath from "./Math.js";
  5. const removeDuplicatesEpsilon = CesiumMath.EPSILON10;
  6. /**
  7. * Removes adjacent duplicate values in an array of values.
  8. *
  9. * @param {any[]} [values] The array of values.
  10. * @param {Function} equalsEpsilon Function to compare values with an epsilon. Boolean equalsEpsilon(left, right, epsilon).
  11. * @param {boolean} [wrapAround=false] Compare the last value in the array against the first value. If they are equal, the last value is removed.
  12. * @param {number[]} [removedIndices=undefined] Store the indices that correspond to the duplicate items removed from the array, if there were any.
  13. * @returns {any[]|undefined} A new array of values with no adjacent duplicate values or the input array if no duplicates were found.
  14. *
  15. * @example
  16. * // Returns [(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0), (1.0, 1.0, 1.0)]
  17. * const values = [
  18. * new Cesium.Cartesian3(1.0, 1.0, 1.0),
  19. * new Cesium.Cartesian3(1.0, 1.0, 1.0),
  20. * new Cesium.Cartesian3(2.0, 2.0, 2.0),
  21. * new Cesium.Cartesian3(3.0, 3.0, 3.0),
  22. * new Cesium.Cartesian3(1.0, 1.0, 1.0)];
  23. * const nonDuplicatevalues = Cesium.PolylinePipeline.removeDuplicates(values, Cartesian3.equalsEpsilon);
  24. *
  25. * @example
  26. * // Returns [(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0)]
  27. * const values = [
  28. * new Cesium.Cartesian3(1.0, 1.0, 1.0),
  29. * new Cesium.Cartesian3(1.0, 1.0, 1.0),
  30. * new Cesium.Cartesian3(2.0, 2.0, 2.0),
  31. * new Cesium.Cartesian3(3.0, 3.0, 3.0),
  32. * new Cesium.Cartesian3(1.0, 1.0, 1.0)];
  33. * const nonDuplicatevalues = Cesium.PolylinePipeline.removeDuplicates(values, Cartesian3.equalsEpsilon, true);
  34. *
  35. * @example
  36. * // Returns [(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0)]
  37. * // removedIndices will be equal to [1, 3, 5]
  38. * const values = [
  39. * new Cesium.Cartesian3(1.0, 1.0, 1.0),
  40. * new Cesium.Cartesian3(1.0, 1.0, 1.0),
  41. * new Cesium.Cartesian3(2.0, 2.0, 2.0),
  42. * new Cesium.Cartesian3(2.0, 2.0, 2.0),
  43. * new Cesium.Cartesian3(3.0, 3.0, 3.0),
  44. * new Cesium.Cartesian3(1.0, 1.0, 1.0)];
  45. * const nonDuplicatevalues = Cesium.PolylinePipeline.removeDuplicates(values, Cartesian3.equalsEpsilon, true);
  46. * @private
  47. */
  48. function arrayRemoveDuplicates(
  49. values,
  50. equalsEpsilon,
  51. wrapAround,
  52. removedIndices
  53. ) {
  54. //>>includeStart('debug', pragmas.debug);
  55. Check.defined("equalsEpsilon", equalsEpsilon);
  56. //>>includeEnd('debug');
  57. if (!defined(values)) {
  58. return undefined;
  59. }
  60. wrapAround = defaultValue(wrapAround, false);
  61. const storeRemovedIndices = defined(removedIndices);
  62. const length = values.length;
  63. if (length < 2) {
  64. return values;
  65. }
  66. let i;
  67. let v0 = values[0];
  68. let v1;
  69. // We only want to create a new array if there are duplicates in the array.
  70. // As such, cleanedValues is undefined until it encounters the first duplicate, if it exists.
  71. let cleanedValues;
  72. let lastCleanIndex = 0;
  73. // removedIndexLCI keeps track of where lastCleanIndex would be if it were sorted into the removedIndices array.
  74. // In case of arrays such as [A, B, C, ..., A, A, A], removedIndices will not be sorted properly without this.
  75. let removedIndexLCI = -1;
  76. for (i = 1; i < length; ++i) {
  77. v1 = values[i];
  78. if (equalsEpsilon(v0, v1, removeDuplicatesEpsilon)) {
  79. if (!defined(cleanedValues)) {
  80. cleanedValues = values.slice(0, i);
  81. lastCleanIndex = i - 1;
  82. removedIndexLCI = 0;
  83. }
  84. if (storeRemovedIndices) {
  85. removedIndices.push(i);
  86. }
  87. } else {
  88. if (defined(cleanedValues)) {
  89. cleanedValues.push(v1);
  90. lastCleanIndex = i;
  91. if (storeRemovedIndices) {
  92. removedIndexLCI = removedIndices.length;
  93. }
  94. }
  95. v0 = v1;
  96. }
  97. }
  98. if (
  99. wrapAround &&
  100. equalsEpsilon(values[0], values[length - 1], removeDuplicatesEpsilon)
  101. ) {
  102. if (storeRemovedIndices) {
  103. if (defined(cleanedValues)) {
  104. removedIndices.splice(removedIndexLCI, 0, lastCleanIndex);
  105. } else {
  106. removedIndices.push(length - 1);
  107. }
  108. }
  109. if (defined(cleanedValues)) {
  110. cleanedValues.length -= 1;
  111. } else {
  112. cleanedValues = values.slice(0, -1);
  113. }
  114. }
  115. return defined(cleanedValues) ? cleanedValues : values;
  116. }
  117. export default arrayRemoveDuplicates;