UNPKG

@wider/utils_proto

Version:

A set of extensions to basic objects giving uniform behaviour in various technical environments

202 lines (186 loc) 7.89 kB
'use strict'; const $moduleName = "@wider/utils_proto/proto_array"; /** * @copyright Copyright (C) 1985..2021 Martin Baker. http://y-d-r.co.uk * @author Martin W Baker * @license ISC Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ /** * A prototype extender for Array or array like objects * * Array prototype extensions - basic utilities * * This provides a collection of methods that extend the javascript Array object to allow simpler and easier to read code. * * In addition to the members listed on this page, also see the methods listed under Externals / Array. * @module @wider/utils_proto/proto_array * * @example * > require("@wider/utils_proto/proto_array"); * > getAnArrayFromSomeWhere * .permute(); */ //generate a random permutation function permutation(arr, n) { if (arr.length || n <= 0) throw new Error("permutation must be provided an empty array and a positive integer length"); var intermediate = []; for (var i = 0; i < n; i++) intermediate[i] = i; while (intermediate.length > 0) arr.push(intermediate.splice(Math.floor(intermediate.length * Math.random()), 1)[0]); } const arrayPrototypes = { /** * Permutes the order of any array according to a given or self generated permutation * Useful to randomise the members - such as for statistics or to select pictures in a slide show * If the given array is empty and the parameter permutation is a number then the original array is filled with a random permutation of length given - this then can be used to permute other arrays. * @function permute() * @param {array | number} param if is a number that requires the array given to be empty and will be filled with a random permutation of the length given (ie all the numbers 0,, param-1 appear in a random order) * if is an array it must be the same length as the given array and contain all the numbers 0 to length -1 * @returns {array} * @throws when param is a number and the given array is not empty or when a member of perm is not an integer in the correct range * @example * > x=[]; x.permute(6); x * // [ 4, 2, 3, 0, 1, 5 ] * * > y=["a","b","c"].permute(x) * // Thrown: * // Error: permutation item(0)=4 is not a valid number in range [0..2] * // at Array.permute * * > y=["a","b","c","d", "e","f"]; y.permute(x) * // [ "e", "c", "d", "a", "b", "f" ] */ wider_permute: function (perm) { let result; if (this.length === 0) { permutation(this, perm); result = this; } else { result = []; for (let i = 0; i < this.length; i++) { if (perm[i] >= 0 && perm[i] < this.length) result.push(this[perm[i]]); else throw new Error("permutation item(" + i + ")=" + perm[i] + " is not a valid number in range [0.." + (this.length - 1) + "]"); } } return result; }, /** * Same as `.push()</code? except that members that match with == are ignored as duplicates * @function pushUnique() * @param {*} value - the value to be added to the list provided it is not already there * @param {Boolean} [unshift=false] - if true then the result is unshifted rather than pushed * @returns {number} the index of the item in the array - which may be that of its unique predecessor * @example * > x=[1,2,3,4] * // [ 1, 2, 3, 4 ] * > x.pushUnique(3) * // 2 * > x.pushUnique(310) * // 4 * > x * // [ 1, 2, 3, 4, 310 ] */ wider_pushUnique: function (value, unshift = false) { let i; if (typeof value == "string" || !value.key) { for (i = 0; i < this.length; i++) if (this[i] == value) return i; } else { for (i = 0; i < this.length; i++) if (this[i].key == value.key) { this[i] = value; // while the key may be the same the rest of the object might not be return i; } } if (unshift) this.unshift(value); else this.push(value); return this.length - 1; // returns the index of the item just saved }, /** * Generates a function that you may use in [...].sort() which gives a plain ascending sort. This is the same as the default sort. It is provided so you can pick this or another sort where the type of sort is determined by your context . * @function plainSortAsc() * @example * > x=[]; x.permute(6); x * // [ 5, 0, 1, 2, 3, 4 ] * * > x.sort(x.plainSortAsc) * // [ 0, 1, 2, 3, 4, 5 ] */ wider_plainSortAsc: function (myLeft, myRight) { return ((myLeft == myRight) ? 0 : (myLeft > myRight) ? 1 : -1); }, /** * Provide a function that you may use in [...].sort() which gives a plain descending sort. * @function plainSortDesc() * @example * > x=[]; x.permute(6); x * // [ 1, 2, 0, 4, 5, 3 ] * * > x.sort(x.plainSortDesc) * // [ 5, 4, 3, 2, 1, 0 ] */ wider_plainSortDesc: function (myLeft, myRight) { return ((myLeft == myRight) ? 0 : (myLeft > myRight) ? -1 : 1); }, /** * Provide a function that you may use in [...].sort() which gives a numeric ascending sort. * * May be used in Externals / Array / KeySort * @function numericSortAsc() */ wider_numericSortAsc: function (myLeft, myRight) { myLeft = parseFloat(myLeft); myRight = parseFloat(myRight); return ((myLeft == myRight) ? 0 : (myLeft > myRight) ? 1 : -1); }, /** * Provide a function that you may use in the standard javascript [...].sort() where the members of the array are objects. You provide the name of the key shared by the objects on which to sort and the sort function that is to be applied * @function keySort() * @param {objectname} keyName - name of the property of the object on which to sort * @param {function} sorter - a sort method such as [].numericSortAsc or a sort object per the standard javascript specification of your own creation * @example * > x=[ {a : "a", key:"last"}, {key:"middle", value: {z:1}}, {c: 3} ]; * // [ * // { a: "a", key: "last" }, * // { key: "middle", value: { z: 1 } }, * // { c: 3 } * // ] * * > x.sort(x.keySort("key", x.plainSortAsc)) * // [ * // { c: 3 }, * // { a: "a", key: "last" }, * // { key: "middle", value: { z: 1 } } * // ] */ wider_keySort: function (keyName, sorter) { return function (myLeft, myRight) { return sorter(myLeft[keyName], myRight[keyName]); }; } }; /** * @private * @param {object} target - this will normally be the javascript Array object - but if you dont want to change that object then provide your own equivalent */ function assignArray(target = Array) { /* set the prototype of String or if it already exists then extend it */ if (target.prototype) Object.assign(target.prototype, arrayPrototypes); else target.prototype = arrayPrototypes; return arrayPrototypes; } assignArray.$moduleName = $moduleName; if (global.$wider) global.$wider.registry.register($moduleName, assignArray, "protoArray", "utils"); export default assignArray;