ordered-numbers.class.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. export class OrderedNumbers {
  2. constructor(private numbers: number[] = [], private readonly unique = true) {
  3. if (!this.isValid) {
  4. this.sort();
  5. if (this.unique) {
  6. this.makeUnique();
  7. }
  8. }
  9. }
  10. private get isValid(): boolean {
  11. for (const [index, number] of this.numbers.entries()) {
  12. if (index > 0 && number < this.numbers[index - 1]) {
  13. return false;
  14. }
  15. }
  16. return this.isUnique;
  17. }
  18. private sort(): number[] {
  19. return this.numbers.sort((a, b) => a - b);
  20. }
  21. private static filterUnique(
  22. value: number,
  23. index: number,
  24. numbers: number[],
  25. ): boolean {
  26. return numbers.indexOf(value) === index;
  27. }
  28. private get isUnique(): boolean {
  29. return this.numbers.filter(OrderedNumbers.filterUnique).length ===
  30. this.numbers.length;
  31. }
  32. private makeUnique(): number[] {
  33. this.numbers = this.numbers.filter(OrderedNumbers.filterUnique);
  34. return this.numbers;
  35. }
  36. public get list(): number[] {
  37. return this.numbers;
  38. }
  39. public get max(): number {
  40. return this.numbers.slice(-1)[0];
  41. }
  42. public contains(number: number): boolean {
  43. return this.numbers.indexOf(number) !== -1;
  44. }
  45. public add(number: number): number[] {
  46. if (this.unique && this.contains(number)) {
  47. return this.list;
  48. }
  49. const max = this.max;
  50. this.numbers.push(number);
  51. if (max < number) {
  52. return this.list;
  53. }
  54. this.sort();
  55. return this.list;
  56. }
  57. public remove(number: number): number[] {
  58. if (!this.contains(number)) {
  59. return this.list;
  60. }
  61. this.numbers = this.list.filter((n) => n !== number);
  62. return this.numbers;
  63. }
  64. public findNextLargerValue(
  65. number: number,
  66. fromIndex = 0,
  67. toIndex = this.numbers.length,
  68. ): number | undefined {
  69. if (this.list.length === 0) {
  70. return undefined;
  71. }
  72. if (number > this.max) {
  73. return undefined;
  74. }
  75. if (number < this.numbers[0]) {
  76. return this.numbers[0];
  77. }
  78. if (this.contains(number)) {
  79. return this.numbers[this.numbers.indexOf(number) + 1];
  80. }
  81. const length = toIndex - fromIndex;
  82. if (length > 1) {
  83. const middle = fromIndex + Math.floor(length / 2);
  84. return this.numbers[middle] > number
  85. ? this.findNextLargerValue(number, fromIndex, middle)
  86. : this.findNextLargerValue(number, middle + 1, toIndex);
  87. }
  88. return this.numbers[fromIndex] > number
  89. ? this.numbers[fromIndex]
  90. : this.numbers[fromIndex + 1];
  91. }
  92. }