mathjs
Version:
Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser and offers an integrated solution to work with numbers, big numbers, complex numbers, units, and matrices.
191 lines (170 loc) • 5.98 kB
JavaScript
module.exports = function (math) {
var util = require('../../util/index'),
Matrix = require('../../type/Matrix'),
Index = require('../../type/Index'),
array = util.array,
isString = util.string.isString,
isArray = Array.isArray;
/**
* Get or set a subset of a matrix or string
*
* Usage:
* // retrieve subset:
* var subset = math.subset(value, index)
*
* // replace subset:
* var value = math.subset(value, index, replacement [, defaultValue])
*
* Where:
* {Array | Matrix | String} value An array, matrix, or string
* {Index} index An index containing ranges for each
* dimension
* {*} replacement An array, matrix, or scalar
* {*} [defaultValue] Default value, filled in on new entries when
* the matrix is resized. If not provided,
* new matrix elements will be left undefined.
* @param args
* @return res
*/
math.subset = function subset (args) {
switch (arguments.length) {
case 2: // get subset
return _getSubset(arguments[0], arguments[1]);
// intentional fall through
case 3: // set subset
case 4: // set subset with default value
return _setSubset(arguments[0], arguments[1], arguments[2], arguments[3]);
default: // wrong number of arguments
throw new math.error.ArgumentsError('subset', arguments.length, 2, 4);
}
};
/**
* Retrieve a subset of an value such as an Array, Matrix, or String
* @param {Array | Matrix | String} value Object from which to get a subset
* @param {Index} index An index containing ranges for each
* dimension
* @returns {Array | Matrix | *} subset
* @private
*/
function _getSubset(value, index) {
var m, subset;
if (isArray(value)) {
m = new Matrix(value);
subset = m.subset(index);
return subset.valueOf();
}
else if (value instanceof Matrix) {
return value.subset(index);
}
else if (isString(value)) {
return _getSubstring(value, index);
}
else {
throw new math.error.UnsupportedTypeError('subset', math['typeof'](value));
}
}
/**
* 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 (!(index instanceof Index)) {
// TODO: better error message
throw new TypeError('Index expected');
}
if (index.size().length != 1) {
throw new math.error.DimensionError(index.size().length, 1);
}
var range = index.range(0);
var substr = '';
var strLen = str.length;
range.forEach(function (v) {
array.validateIndex(v, strLen);
substr += str.charAt(v);
});
return substr;
}
/**
* Replace a subset in an value such as an Array, Matrix, or String
* @param {Array | Matrix | String} value Object to be replaced
* @param {Index} index An index containing ranges for each
* dimension
* @param {Array | Matrix | *} replacement
* @param {*} [defaultValue] Default value, filled in on new entries when
* the matrix is resized. If not provided,
* new matrix elements will be left undefined.
* @returns {*} result
* @private
*/
function _setSubset(value, index, replacement, defaultValue) {
var m;
if (isArray(value)) {
m = new Matrix(math.clone(value));
m.subset(index, replacement, defaultValue);
return m.valueOf();
}
else if (value instanceof Matrix) {
return value.clone().subset(index, replacement, defaultValue);
}
else if (isString(value)) {
return _setSubstring(value, index, replacement, defaultValue);
}
else {
throw new math.error.UnsupportedTypeError('subset', math['typeof'](value));
}
}
/**
* 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 instanceof Index)) {
// TODO: better error message
throw new TypeError('Index expected');
}
if (index.size().length != 1) {
throw new math.error.DimensionError(index.size().length, 1);
}
if (defaultValue !== undefined) {
if (!isString(defaultValue) || defaultValue.length !== 1) {
throw new TypeError('Single character expected as defaultValue');
}
}
else {
defaultValue = ' ';
}
var range = index.range(0);
var len = range.size()[0];
if (len != replacement.length) {
throw new math.error.DimensionError(range.size()[0], replacement.length);
}
// copy the string into an array with characters
var strLen = str.length;
var chars = [];
for (var i = 0; i < strLen; i++) {
chars[i] = str.charAt(i);
}
range.forEach(function (v, i) {
array.validateIndex(v);
chars[v] = replacement.charAt(i);
});
// initialize undefined characters with a space
if (chars.length > strLen) {
for (i = strLen - 1, len = chars.length; i < len; i++) {
if (!chars[i]) {
chars[i] = defaultValue;
}
}
}
return chars.join('');
}
};