UNPKG

mathjs

Version:

Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser with support for symbolic computation, comes with a large set of built-in functions and constants, and offers an integrated solution to work with dif

233 lines (198 loc) 7.19 kB
'use strict' const clone = require('../../utils/object').clone const validateIndex = require('../../utils/array').validateIndex const getSafeProperty = require('../../utils/customs').getSafeProperty const setSafeProperty = require('../../utils/customs').setSafeProperty const DimensionError = require('../../error/DimensionError') function factory (type, config, load, typed) { const matrix = load(require('../../type/matrix/function/matrix')) /** * Get or set a subset of a matrix or string. * * Syntax: * math.subset(value, index) // retrieve a subset * math.subset(value, index, replacement [, defaultValue]) // replace a subset * * Examples: * * // get a subset * const d = [[1, 2], [3, 4]] * math.subset(d, math.index(1, 0)) // returns 3 * math.subset(d, math.index([0, 1], 1)) // returns [[2], [4]] * * // replace a subset * const e = [] * const f = math.subset(e, math.index(0, [0, 2]), [5, 6]) // f = [[5, 6]] * const g = math.subset(f, math.index(1, 1), 7, 0) // g = [[5, 6], [0, 7]] * * See also: * * size, resize, squeeze, index * * @param {Array | Matrix | string} matrix An array, matrix, or string * @param {Index} index An index containing ranges for each * dimension * @param {*} [replacement] An array, matrix, or scalar. * If provided, the subset is replaced with replacement. * If not provided, the subset is returned * @param {*} [defaultValue=undefined] Default value, filled in on new entries when * the matrix is resized. If not provided, * math.matrix elements will be left undefined. * @return {Array | Matrix | string} Either the retrieved subset or the updated matrix. */ const subset = typed('subset', { // get subset 'Array, Index': function (value, index) { const m = matrix(value) const subset = m.subset(index) // returns a Matrix return index.isScalar() ? subset : subset.valueOf() // return an Array (like the input) }, 'Matrix, Index': function (value, index) { return value.subset(index) }, 'Object, Index': _getObjectProperty, 'string, Index': _getSubstring, // set subset 'Array, Index, any': function (value, index, replacement) { return matrix(clone(value)) .subset(index, replacement, undefined) .valueOf() }, 'Array, Index, any, any': function (value, index, replacement, defaultValue) { return matrix(clone(value)) .subset(index, replacement, defaultValue) .valueOf() }, 'Matrix, Index, any': function (value, index, replacement) { return value.clone().subset(index, replacement) }, 'Matrix, Index, any, any': function (value, index, replacement, defaultValue) { return value.clone().subset(index, replacement, defaultValue) }, 'string, Index, string': _setSubstring, 'string, Index, string, string': _setSubstring, 'Object, Index, any': _setObjectProperty }) subset.toTex = undefined // use default template return subset /** * Retrieve a subset of a string * @param {string} str string from which to get a substring * @param {Index} index An index containing ranges for each dimension * @returns {string} substring * @private */ function _getSubstring (str, index) { if (!type.isIndex(index)) { // TODO: better error message throw new TypeError('Index expected') } if (index.size().length !== 1) { throw new DimensionError(index.size().length, 1) } // validate whether the range is out of range const strLen = str.length validateIndex(index.min()[0], strLen) validateIndex(index.max()[0], strLen) const range = index.dimension(0) let substr = '' range.forEach(function (v) { substr += str.charAt(v) }) return substr } /** * Replace a substring in a string * @param {string} str string to be replaced * @param {Index} index An index containing ranges for each dimension * @param {string} replacement Replacement string * @param {string} [defaultValue] Default value to be uses when resizing * the string. is ' ' by default * @returns {string} result * @private */ function _setSubstring (str, index, replacement, defaultValue) { if (!index || index.isIndex !== true) { // TODO: better error message throw new TypeError('Index expected') } if (index.size().length !== 1) { throw new DimensionError(index.size().length, 1) } if (defaultValue !== undefined) { if (typeof defaultValue !== 'string' || defaultValue.length !== 1) { throw new TypeError('Single character expected as defaultValue') } } else { defaultValue = ' ' } const range = index.dimension(0) const len = range.size()[0] if (len !== replacement.length) { throw new DimensionError(range.size()[0], replacement.length) } // validate whether the range is out of range const strLen = str.length validateIndex(index.min()[0]) validateIndex(index.max()[0]) // copy the string into an array with characters const chars = [] for (let i = 0; i < strLen; i++) { chars[i] = str.charAt(i) } range.forEach(function (v, i) { chars[v] = replacement.charAt(i[0]) }) // initialize undefined characters with a space if (chars.length > strLen) { for (let i = strLen - 1, len = chars.length; i < len; i++) { if (!chars[i]) { chars[i] = defaultValue } } } return chars.join('') } } /** * Retrieve a property from an object * @param {Object} object * @param {Index} index * @return {*} Returns the value of the property * @private */ function _getObjectProperty (object, index) { if (index.size().length !== 1) { throw new DimensionError(index.size(), 1) } const key = index.dimension(0) if (typeof key !== 'string') { throw new TypeError('String expected as index to retrieve an object property') } return getSafeProperty(object, key) } /** * Set a property on an object * @param {Object} object * @param {Index} index * @param {*} replacement * @return {*} Returns the updated object * @private */ function _setObjectProperty (object, index, replacement) { if (index.size().length !== 1) { throw new DimensionError(index.size(), 1) } const key = index.dimension(0) if (typeof key !== 'string') { throw new TypeError('String expected as index to retrieve an object property') } // clone the object, and apply the property to the clone const updated = clone(object) setSafeProperty(updated, key, replacement) return updated } exports.name = 'subset' exports.factory = factory