7b4a9645faca77d7ad0c206b347019a76624fd129ab534541715208e56a706b00839d4d46d3e5cd820366e45b2cf1e8d882b51f9a617eac619d83903c74d26 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import {isObject} from './../helpers/object';
  2. import {rangeEach} from './../helpers/number';
  3. import {stringify} from './../helpers/mixed';
  4. /**
  5. * @class SamplesGenerator
  6. * @util
  7. */
  8. class SamplesGenerator {
  9. /**
  10. * Number of samples to take of each value length.
  11. *
  12. * @type {Number}
  13. */
  14. static get SAMPLE_COUNT() {
  15. return 3;
  16. }
  17. constructor(dataFactory) {
  18. /**
  19. * Samples prepared for calculations.
  20. *
  21. * @type {Map}
  22. * @default {null}
  23. */
  24. this.samples = null;
  25. /**
  26. * Function which give the data to collect samples.
  27. *
  28. * @type {Function}
  29. */
  30. this.dataFactory = dataFactory;
  31. /**
  32. * Custom number of samples to take of each value length.
  33. *
  34. * @type {Number}
  35. * @default {null}
  36. */
  37. this.customSampleCount = null;
  38. /**
  39. * `true` if duplicate samples collection should be allowed, `false` otherwise.
  40. *
  41. * @type {Boolean}
  42. * @default {false}
  43. */
  44. this.allowDuplicates = false;
  45. }
  46. /**
  47. * Get the sample count for this instance.
  48. *
  49. * @returns {Number}
  50. */
  51. getSampleCount() {
  52. if (this.customSampleCount) {
  53. return this.customSampleCount;
  54. }
  55. return SamplesGenerator.SAMPLE_COUNT;
  56. };
  57. /**
  58. * Set the sample count.
  59. *
  60. * @param {Number} sampleCount Number of samples to be collected.
  61. */
  62. setSampleCount(sampleCount) {
  63. this.customSampleCount = sampleCount;
  64. }
  65. /**
  66. * Set if the generator should accept duplicate values.
  67. *
  68. * @param {Boolean} allowDuplicates `true` to allow duplicate values.
  69. */
  70. setAllowDuplicates(allowDuplicates) {
  71. this.allowDuplicates = allowDuplicates;
  72. }
  73. /**
  74. * Generate samples for row. You can control which area should be sampled by passing `rowRange` object and `colRange` object.
  75. *
  76. * @param {Object|Number} rowRange
  77. * @param {Object} colRange
  78. * @returns {Object}
  79. */
  80. generateRowSamples(rowRange, colRange) {
  81. return this.generateSamples('row', colRange, rowRange);
  82. }
  83. /**
  84. * Generate samples for column. You can control which area should be sampled by passing `colRange` object and `rowRange` object.
  85. *
  86. * @param {Object} colRange Column index.
  87. * @param {Object} rowRange Column index.
  88. * @returns {Object}
  89. */
  90. generateColumnSamples(colRange, rowRange) {
  91. return this.generateSamples('col', rowRange, colRange);
  92. }
  93. /**
  94. * Generate collection of samples.
  95. *
  96. * @param {String} type Type to generate. Can be `col` or `row`.
  97. * @param {Object} range
  98. * @param {Object|Number} specifierRange
  99. * @returns {Map}
  100. */
  101. generateSamples(type, range, specifierRange) {
  102. const samples = new Map();
  103. if (typeof specifierRange === 'number') {
  104. specifierRange = {from: specifierRange, to: specifierRange};
  105. }
  106. rangeEach(specifierRange.from, specifierRange.to, (index) => {
  107. const sample = this.generateSample(type, range, index);
  108. samples.set(index, sample);
  109. });
  110. return samples;
  111. }
  112. /**
  113. * Generate sample for specified type (`row` or `col`).
  114. *
  115. * @param {String} type Samples type `row` or `col`.
  116. * @param {Object} range
  117. * @param {Number} specifierValue
  118. * @returns {Map}
  119. */
  120. generateSample(type, range, specifierValue) {
  121. const samples = new Map();
  122. let sampledValues = [];
  123. let length;
  124. rangeEach(range.from, range.to, (index) => {
  125. let value;
  126. if (type === 'row') {
  127. value = this.dataFactory(specifierValue, index);
  128. } else if (type === 'col') {
  129. value = this.dataFactory(index, specifierValue);
  130. } else {
  131. throw new Error('Unsupported sample type');
  132. }
  133. if (isObject(value)) {
  134. length = Object.keys(value).length;
  135. } else if (Array.isArray(value)) {
  136. length = value.length;
  137. } else {
  138. length = stringify(value).length;
  139. }
  140. if (!samples.has(length)) {
  141. samples.set(length, {
  142. needed: this.getSampleCount(),
  143. strings: [],
  144. });
  145. }
  146. let sample = samples.get(length);
  147. if (sample.needed) {
  148. let duplicate = sampledValues.indexOf(value) > -1;
  149. if (!duplicate || this.allowDuplicates) {
  150. let computedKey = type === 'row' ? 'col' : 'row';
  151. sample.strings.push({value, [computedKey]: index});
  152. sampledValues.push(value);
  153. sample.needed--;
  154. }
  155. }
  156. });
  157. return samples;
  158. }
  159. }
  160. export default SamplesGenerator;