subset.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import { isIndex } from '../../utils/is.js';
  2. import { clone } from '../../utils/object.js';
  3. import { validateIndex } from '../../utils/array.js';
  4. import { getSafeProperty, setSafeProperty } from '../../utils/customs.js';
  5. import { DimensionError } from '../../error/DimensionError.js';
  6. import { factory } from '../../utils/factory.js';
  7. var name = 'subset';
  8. var dependencies = ['typed', 'matrix'];
  9. export var createSubset = /* #__PURE__ */factory(name, dependencies, _ref => {
  10. var {
  11. typed,
  12. matrix
  13. } = _ref;
  14. /**
  15. * Get or set a subset of a matrix or string.
  16. *
  17. * Syntax:
  18. * math.subset(value, index) // retrieve a subset
  19. * math.subset(value, index, replacement [, defaultValue]) // replace a subset
  20. *
  21. * Examples:
  22. *
  23. * // get a subset
  24. * const d = [[1, 2], [3, 4]]
  25. * math.subset(d, math.index(1, 0)) // returns 3
  26. * math.subset(d, math.index([0, 1], 1)) // returns [[2], [4]]
  27. *
  28. * // replace a subset
  29. * const e = []
  30. * const f = math.subset(e, math.index(0, [0, 2]), [5, 6]) // f = [[5, 6]] and e = [[5, 0, 6]]
  31. * const g = math.subset(f, math.index(1, 1), 7, 0) // g = [[5, 6], [0, 7]]
  32. *
  33. * // get submatrix using ranges
  34. * const M = [
  35. * [1,2,3],
  36. * [4,5,6],
  37. * [7,8,9]
  38. * ]
  39. * math.subset(M, math.index(math.range(0,2), math.range(0,3))) // [[1,2,3],[4,5,6]]
  40. *
  41. * See also:
  42. *
  43. * size, resize, squeeze, index
  44. *
  45. * @param {Array | Matrix | string} matrix An array, matrix, or string
  46. * @param {Index} index
  47. * For each dimension of the target, specifies an index or a list of
  48. * indices to fetch or set. `subset` uses the cartesian product of
  49. * the indices specified in each dimension.
  50. * @param {*} [replacement] An array, matrix, or scalar.
  51. * If provided, the subset is replaced with replacement.
  52. * If not provided, the subset is returned
  53. * @param {*} [defaultValue=undefined] Default value, filled in on new entries when
  54. * the matrix is resized. If not provided,
  55. * math.matrix elements will be left undefined.
  56. * @return {Array | Matrix | string} Either the retrieved subset or the updated matrix.
  57. */
  58. return typed(name, {
  59. // get subset
  60. 'Array, Index': function ArrayIndex(value, index) {
  61. var m = matrix(value);
  62. var subset = m.subset(index); // returns a Matrix
  63. return index.isScalar() ? subset : subset.valueOf(); // return an Array (like the input)
  64. },
  65. 'Matrix, Index': function MatrixIndex(value, index) {
  66. return value.subset(index);
  67. },
  68. 'Object, Index': _getObjectProperty,
  69. 'string, Index': _getSubstring,
  70. // set subset
  71. 'Array, Index, any': function ArrayIndexAny(value, index, replacement) {
  72. return matrix(clone(value)).subset(index, replacement, undefined).valueOf();
  73. },
  74. 'Array, Index, any, any': function ArrayIndexAnyAny(value, index, replacement, defaultValue) {
  75. return matrix(clone(value)).subset(index, replacement, defaultValue).valueOf();
  76. },
  77. 'Matrix, Index, any': function MatrixIndexAny(value, index, replacement) {
  78. return value.clone().subset(index, replacement);
  79. },
  80. 'Matrix, Index, any, any': function MatrixIndexAnyAny(value, index, replacement, defaultValue) {
  81. return value.clone().subset(index, replacement, defaultValue);
  82. },
  83. 'string, Index, string': _setSubstring,
  84. 'string, Index, string, string': _setSubstring,
  85. 'Object, Index, any': _setObjectProperty
  86. });
  87. });
  88. /**
  89. * Retrieve a subset of a string
  90. * @param {string} str string from which to get a substring
  91. * @param {Index} index An index or list of indices (character positions)
  92. * @returns {string} substring
  93. * @private
  94. */
  95. function _getSubstring(str, index) {
  96. if (!isIndex(index)) {
  97. // TODO: better error message
  98. throw new TypeError('Index expected');
  99. }
  100. if (index.size().length !== 1) {
  101. throw new DimensionError(index.size().length, 1);
  102. }
  103. // validate whether the range is out of range
  104. var strLen = str.length;
  105. validateIndex(index.min()[0], strLen);
  106. validateIndex(index.max()[0], strLen);
  107. var range = index.dimension(0);
  108. var substr = '';
  109. range.forEach(function (v) {
  110. substr += str.charAt(v);
  111. });
  112. return substr;
  113. }
  114. /**
  115. * Replace a substring in a string
  116. * @param {string} str string to be replaced
  117. * @param {Index} index An index or list of indices (character positions)
  118. * @param {string} replacement Replacement string
  119. * @param {string} [defaultValue] Default value to be uses when resizing
  120. * the string. is ' ' by default
  121. * @returns {string} result
  122. * @private
  123. */
  124. function _setSubstring(str, index, replacement, defaultValue) {
  125. if (!index || index.isIndex !== true) {
  126. // TODO: better error message
  127. throw new TypeError('Index expected');
  128. }
  129. if (index.size().length !== 1) {
  130. throw new DimensionError(index.size().length, 1);
  131. }
  132. if (defaultValue !== undefined) {
  133. if (typeof defaultValue !== 'string' || defaultValue.length !== 1) {
  134. throw new TypeError('Single character expected as defaultValue');
  135. }
  136. } else {
  137. defaultValue = ' ';
  138. }
  139. var range = index.dimension(0);
  140. var len = range.size()[0];
  141. if (len !== replacement.length) {
  142. throw new DimensionError(range.size()[0], replacement.length);
  143. }
  144. // validate whether the range is out of range
  145. var strLen = str.length;
  146. validateIndex(index.min()[0]);
  147. validateIndex(index.max()[0]);
  148. // copy the string into an array with characters
  149. var chars = [];
  150. for (var i = 0; i < strLen; i++) {
  151. chars[i] = str.charAt(i);
  152. }
  153. range.forEach(function (v, i) {
  154. chars[v] = replacement.charAt(i[0]);
  155. });
  156. // initialize undefined characters with a space
  157. if (chars.length > strLen) {
  158. for (var _i = strLen - 1, _len = chars.length; _i < _len; _i++) {
  159. if (!chars[_i]) {
  160. chars[_i] = defaultValue;
  161. }
  162. }
  163. }
  164. return chars.join('');
  165. }
  166. /**
  167. * Retrieve a property from an object
  168. * @param {Object} object
  169. * @param {Index} index
  170. * @return {*} Returns the value of the property
  171. * @private
  172. */
  173. function _getObjectProperty(object, index) {
  174. if (index.size().length !== 1) {
  175. throw new DimensionError(index.size(), 1);
  176. }
  177. var key = index.dimension(0);
  178. if (typeof key !== 'string') {
  179. throw new TypeError('String expected as index to retrieve an object property');
  180. }
  181. return getSafeProperty(object, key);
  182. }
  183. /**
  184. * Set a property on an object
  185. * @param {Object} object
  186. * @param {Index} index
  187. * @param {*} replacement
  188. * @return {*} Returns the updated object
  189. * @private
  190. */
  191. function _setObjectProperty(object, index, replacement) {
  192. if (index.size().length !== 1) {
  193. throw new DimensionError(index.size(), 1);
  194. }
  195. var key = index.dimension(0);
  196. if (typeof key !== 'string') {
  197. throw new TypeError('String expected as index to retrieve an object property');
  198. }
  199. // clone the object, and apply the property to the clone
  200. var updated = clone(object);
  201. setSafeProperty(updated, key, replacement);
  202. return updated;
  203. }