UNPKG

handyscript

Version:

A set of useful modules that makes the javascript development context easier

1,060 lines (1,052 loc) 34.7 kB
//// ------------------------------- HANDY ARRAYS © Handy-JS 5m/21d/23y ------------------------------- Array.prototype.shuffle = function () { if (this.length === 0) return this; for (let i = this.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [this[i], this[j]] = [this[j], this[i]]; } return this; }; Array.prototype.bubbleSort = function (order = "asc") { if (this.length === 0) return this; for (let i = 0; i < this.length; i++) { for (let j = 0; j < this.length - i - 1; j++) { if (order === "asc" ? this[j] > this[j + 1] : this[j] < this[j + 1]) { [this[j], this[j + 1]] = [this[j + 1], this[j]]; } } } return this; }; Array.prototype.selectionSort = function (order = "asc") { if (this.length === 0) return this; for (let i = 0; i < this.length; i++) { let min = i; for (let j = i + 1; j < this.length; j++) { if (order === "asc" ? this[j] < this[min] : this[j] > this[min]) min = j; } if (min !== i) [this[i], this[min]] = [this[min], this[i]]; } return this; }; Array.prototype.insertionSort = function (order = "asc") { if (this.length === 0) return this; for (let i = 1; i < this.length; i++) { let j = i - 1; let temp = this[i]; while (j >= 0 && (order === "asc" ? this[j] > temp : this[j] < temp)) { this[j + 1] = this[j]; j--; } this[j + 1] = temp; } return this; }; Array.prototype.mergeSort = function (order = "asc") { if (this.length === 0) return this; const merge = (left, right) => { const result = []; while (left.length && right.length) { if (order === "asc" ? left[0] <= right[0] : left[0] >= right[0]) { result.push(left.shift()); } else { result.push(right.shift()); } } while (left.length) result.push(left.shift()); while (right.length) result.push(right.shift()); return result; }; if (this.length < 2) return this; const middle = Math.floor(this.length / 2); const left = this.slice(0, middle); const right = this.slice(middle, this.length); return merge(left.mergeSort(order), right.mergeSort(order)); }; Array.prototype.quickSort = function (order = "asc") { if (this.length === 0) return this; const partition = (arr, left, right) => { const pivot = arr[Math.floor((right + left) / 2)]; let i = left; let j = right; while (i <= j) { if (order === "asc") { while (arr[i] < pivot) i++; while (arr[j] > pivot) j--; } else { while (arr[i] > pivot) i++; while (arr[j] < pivot) j--; } if (i <= j) { [arr[i], arr[j]] = [arr[j], arr[i]]; i++; j--; } } return i; }; let left = 0; let right = this.length - 1; let index; if (this.length > 1) { index = partition(this, left, right); if (left < index - 1) this.quickSort(order); if (index < right) this.quickSort(order); } return this; }; Array.prototype.heapSort = function (order = "asc") { if (this.length === 0) return this; const heapify = (arr, length, i) => { let largest = i; const left = i * 2 + 1; const right = left + 1; if (left < length && (order === "asc" ? arr[left] > arr[largest] : arr[left] < arr[largest])) largest = left; if (right < length && (order === "asc" ? arr[right] > arr[largest] : arr[right] < arr[largest])) largest = right; if (largest !== i) { [arr[i], arr[largest]] = [arr[largest], arr[i]]; heapify(arr, length, largest); } }; const buildMaxHeap = (arr) => { for (let i = Math.floor(arr.length / 2); i >= 0; i--) heapify(arr, arr.length, i); return arr; }; buildMaxHeap(this); for (let i = this.length - 1; i > 0; i--) { [this[0], this[i]] = [this[i], this[0]]; heapify(this, i, 0); } return this; }; // THIS: only support array of numbers Array.prototype.countingSort = function (order = "asc") { if (this.length === 0) return this; if (!this.every(num => typeof num === "number")) throw new Error("countingSort only support array of numbers"); const min = Math.min(...this); const max = Math.max(...this); const countBucket = new Array(max - min + 1).fill(0); const start = order === "asc" ? 0 : countBucket.length - 1; const step = order === "asc" ? 1 : -1; for (let i = 0; i < this.length; i++) countBucket[this[i] - min]++; let index = start; for (let i = 0; i < countBucket.length; i++) { while (countBucket[i] > 0) { this[index] = i + min; index += step; countBucket[i]--; } } return this; }; Array.prototype.bucketSort = function (order = "asc") { if (this.length === 0) return this; const buckets = {}; for (const item of this) { const key = item.toString(); if (!buckets[key]) { buckets[key] = []; } buckets[key].push(item); } const sortedKeys = Object.keys(buckets).sort(); const sortedArray = []; for (const key of sortedKeys) { sortedArray.push(...buckets[key]); } return order === "asc" ? sortedArray : sortedArray.reverse(); }; // THIS: only support array of numbers // the radix sort is not working, it's frezzing the browser Array.prototype.radixSort = function (radix = 10, order = "asc") { if (this.length === 0) return this; if (!this.every(num => typeof num === "number")) throw new Error("radixSort only support array of numbers"); // TODO: fix radix sort return this; }; Array.prototype.shellSort = function (order = "asc") { if (this.length === 0) return this; for (let gap = Math.floor(this.length / 2); gap > 0; gap = Math.floor(gap / 2)) { for (let i = gap; i < this.length; i++) { const temp = this[i]; let j; for (j = i; j >= gap && (order === "asc" ? this[j - gap] > temp : this[j - gap] < temp); j -= gap) { this[j] = this[j - gap]; } this[j] = temp; } } return this; }; Array.prototype.chunk = function (size = 1) { if (size < 1) return this; return this.slice(0, Math.ceil(this.length / size)).reduce((acc, _, i) => [...acc, this.slice(size * i, size * i + size)], []); }; Array.prototype.compact = function () { if (this.length === 0) return this; return this.filter(item => item); }; Array.prototype.filterNullish = function () { if (this.length === 0) return this; return this.filter(item => item != null); }; Array.prototype.unique = function () { if (this.length === 0) return this; return [...new Set(this)]; }; Array.prototype.countBy = function (callback) { if (this.length === 0) return this; return this.reduce((acc, val) => { const key = callback(val); acc[key] = (acc[key] || 0) + 1; return acc; }, {}); }; Array.prototype.binarySearch = function (target, sortalgo) { if (this.length === 0) return -1; // swith between the sort algorithms let sortedArray = []; switch (sortalgo) { case 'bubble': sortedArray = this.bubbleSort(); break; case 'selection': sortedArray = this.selectionSort(); break; case 'insertion': sortedArray = this.insertionSort(); break; case 'merge': sortedArray = this.mergeSort(); break; case 'quick': sortedArray = this.quickSort(); break; case 'heap': sortedArray = this.heapSort(); break; case 'shell': sortedArray = this.shellSort(); break; case 'bucket': sortedArray = this.bucketSort(); break; default: sortedArray = this.sort(); break; } // binary search let start = 0; let end = sortedArray.length - 1; while (start <= end) { const mid = Math.floor((start + end) / 2); if (sortedArray[mid] === target) return mid; if (sortedArray[mid] < target) start = mid + 1; else end = mid - 1; } return -1; }; Array.prototype.clear = function () { if (this.length === 0) return this; this.length = 0; return this; }; Array.prototype.copy = function () { if (this.length === 0) return this; return [...this]; }; Array.prototype.sample = function (quantity = 1) { if (this.length === 0) return this; if (quantity < 1) return []; if (quantity === 1) return this[Math.randomInt(this.length)]; return this.sort(() => Math.random() - Math.random()).slice(0, quantity); }; Array.prototype.count = function (target) { if (this.length === 0) return 0; return this.filter(item => item === target).length; }; Array.prototype.differ = function (other) { if (this.length === 0) return this; return this.filter(item => !other.includes(item)); }; String.prototype.toCapitalCase = function () { return this.split(" ").map((word) => { return word[0].toUpperCase() + word.slice(1); }).join(" "); }; String.prototype.toLocaleCapitalCase = function (locales) { return this.split(" ").map((word) => { return word[0].toLocaleUpperCase(locales) + word.slice(1); }).join(" "); }; String.prototype.toCamelCase = function () { return this.split(" ").map((word, index) => { return index === 0 ? word[0].toLowerCase() + word.slice(1) : word[0].toUpperCase() + word.slice(1); }).join(""); }; String.prototype.toLocaleCamelCase = function (locales) { return this.split(" ").map((word, index) => { return index === 0 ? word[0].toLocaleLowerCase(locales) + word.slice(1) : word[0].toLocaleUpperCase(locales) + word.slice(1); }).join(""); }; String.prototype.reverse = function () { return [...this].reverse().join(""); }; String.prototype.indexesOf = function (target, startPosition) { let indexes = []; let index = this.indexOf(target, startPosition); while (index !== -1) { indexes.push(index); index = this.indexOf(target, index + 1); } return indexes; }; String.prototype.compare = function (target) { return this.localeCompare(target); }; String.prototype.equals = function (target, position = 0) { return [...this].splice(position).join("") === [...target].splice(position).join(""); }; String.prototype.equalsIgnoreCase = function (target, position = 0, locales) { return [...this.toLocaleLowerCase(locales)].splice(position).join("") === [...target.toLocaleLowerCase(locales)].splice(position).join(""); }; String.prototype.escape = function (isForAttribute = false) { let str = this; if (isForAttribute) { str = str.replace(/"/g, "&quot;"); } return str.replace(/[\n\r\t\v\f\b]/g, "").replace(/\s+/g, " ").replace(/[\u0000-\u001F]/g, ""); }; String.prototype.sample = function (wordCount = 0, separator = " ") { let words = this.split(separator); if (wordCount === 0 || wordCount > words.length || wordCount < 0) { return words.slice(0, Math.randomInt(this.length)).join(separator); } return words.slice(0, wordCount).join(separator); }; String.prototype.size = function (separator = " ") { return this.split(separator).length; }; //// ------------------------------- HANDY MATH © Handy-JS 5m/21d/23y ------------------------------- Object.assign(Math, { A: 1.282427129100622636875342568869791727767688927325001192063740432988395529732, B: 1.456074948582689671399595351116543266074274800178127884495013673643948446868, G: 0.624329988543550870992936383100837235703606993625832517625695166735847239685, K: 0.915965594177219015054603514932384110774149374281672134266498119621763019776, TAU: 2 * Math.PI, SQRT3: 1.73205080756887729352744634150587236694280525381038062805580697945193301690880, PHI: 1.61803398874989484820458683436563811772030917980576286213544862270526046281890, DELTA: 4.669201609102990671853203820466201617258185577475768632745651343004134330211, GAMMA: 0.577215664901532860606512090082402431042159335939923598805767234884867726777, ZETA3: 1.202056903159594285399738161511449990764986292340498881792271555341838205786, THETA: 0.6434105463, KAPPA: 0.764223653589220662990698731250092320971690526083222067341264027404987097155, randomInt(max, min = 0) { return Math.floor(Math.random() * (max - min + 1)) + min; }, clamp(value, min, max) { return Math.min(Math.max(value, min), max); }, lerp(start, end, t) { return start * (1 - t) + end * t; }, map(value, inputMin, inputMax, outputMin, outputMax) { const inputRange = inputMax - inputMin; const outputRange = outputMax - outputMin; const normalizedValue = (value - inputMin) / inputRange; return outputMin + normalizedValue * outputRange; } }); //// ------------------------------- HANDY NUMBER © Handy-JS 6m/2d/23y ------------------------------- Number.prototype.toHuman = function () { const num = this.valueOf(); const si = [ { value: 1, symbol: "" }, { value: 1E3, symbol: "K" }, { value: 1E6, symbol: "M" }, { value: 1E9, symbol: "B" }, { value: 1E12, symbol: "T" }, { value: 1E15, symbol: "P" }, { value: 1E18, symbol: "E" }, ]; const rx = /\.0+$|(\.[0-9]*[1-9])0+$/; let i; for (i = si.length - 1; i > 0; i--) if (num >= si[i].value) break; return (num / si[i].value).toFixed(2).replace(rx, "$1") + si[i].symbol; }; Number.prototype.toReadable = function (separator = "-") { const num = this.valueOf(); const rx = /(\d+)(\d{3})/; return String(num).replace(/^\d+/, function (w) { while (rx.test(w)) { w = w.replace(rx, "$1" + separator + "$2"); } return w; }); }; //// ------------------------------- HANDY OPERATORS © Handy-JS 5m/21d/23y ------------------------------- /** * it returns true if all the arguments are true * @param {boolean[]} args * @example * and(true, true, true) // true */ function and(...args) { return args.every(arg => arg === true); } /** * it returns true if any of the arguments is true * @param {boolean[]} args * @example * or(true, false, false) // true */ function or(...args) { return args.some(arg => arg === true); } /** * it returns the opposite of the argument given * @param {any} arg * @example * not(true) // false */ function not(arg) { return !arg; } /** * the `is` function is used to compare two values if they are truly equal * @param {any} value1 * @param {any} value2 * @example * is(1, 1) // true * is("hello", "hi") // false * // Objects are compared by their keys recursively * const obj1 = {name: "john", age: 20}; * const obj2 = {name: "john", age: 20}; * is(obj1, obj2) // true * * // Functions are compared by their source code * const fn1 = () => console.log("hello"); * const fn2 = () => console.log("hi"); * is(fn1, fn2) // false * * // Dates are compared by their millisecond representation * const date1 = new Date(); * const date2 = new Date(date1.getTime()); * is(date1, date2) // true * * // Regular expressions are compared by their source code * const reg1 = /hello/; * const reg2 = /hi/; * is(reg1, reg2) // false */ function is(value1, value2) { switch (typeof value1) { // compare functions by their source code case 'function': return value1.toString() === value2.toString(); // compare object by keys recursively case 'object': if (or(value1 === null, value2 === null)) { return value1 === value2; } switch (value1.constructor) { // compare dates by their millisecond representation case Date: return value1.getTime() === value2.getTime(); // compare regular expressions by their source code case RegExp: return value1.toString() === value2.toString(); default: if (not(is(value1.constructor, value2.constructor))) { return false; } const keys1 = Object.keys(value1); const keys2 = Object.keys(value2); if (not(is(keys1.length, keys2.length))) { return false; } return keys1.every(key => is(value1[key], value2[key])); } default: return value1 === value2; } } /** * loops through the given iterations and calls the callback function with the index ```i``` as argument * @param {number} iterations// the number of iterations to loop through default is 1 * @param {CallableFunction} cb // the function to call in each iteration with the `index` ```i``` as argument * @param {number} index // the starting index by default it's 0 * @param {number} step // the step to increment the index by default it's 1 * @example * loop(5, i=>console.log(i)) // 0 1 2 3 4 */ function loop(iterations = 1, cb, index = 0, step = 1) { for (index; index < iterations; index += step) { cb(index); } } /** * loops through the given `object` and calls the `callback` function with the `key` as argument * @param {object} obj // the object to loop through * @param {CallableFunction} cb // the function to call in each iteration with the `key` as argument * @example * const obj = {name:"ahmed", age: 20}; * objloop(obj, (key, val) => console.log(key, val)) * // name ahmed * // age 20 */ // objloop function with typescript function objloop(obj, cb) { for (const key in obj) { cb(key, obj[key]); } } /** * The `keyloop` function loops through the given `object` and calls the `callback` function with the `key` as argument * @param {object} obj // the object to loop through * @param {CallableFunction} cb // the function to call in each iteration with the `key` as argument * @example * const obj = {name:"ahmed", age: 20}; * keyloop(obj, key => console.log(key)) // name */ function keyloop(obj, cb) { for (const key in obj) { cb(key); } } /** * The `valloop` function loops through the given `object` and calls the `callback` function with the `value` as argument * @param {object} obj // the object to loop through * @param {CallableFunction} cb // the function to call in each iteration with the `value` as argument * @example * const obj = {name:"ahmed", age: 20}; * valloop(obj, val => console.log(val)) // ahmed */ function valloop(obj, cb) { for (const key in obj) { cb(obj[key]); } } /// ======================THE HOPERATORS CLASS: HANDY-JS: OPERATORS METHODS ====================== /** * @namespace HOperators * @description handy operators * @example * // 1 * import HOperators from 'handy-js' * HOperators.and(true, true, true) // true * HOperators.or(true, false, false) // true * // 2 * import {and, or} from 'handy-js' * and(true, true, true) // true * or(true, false, false) // true */ class HOperators { /** * it returns true if all the arguments are true * @memberof HOperators * @param {...any} args * @example * HOperators.and(true, true, true) // true */ static and = and; /** * it returns true if any of the arguments is true * @memberof HOperators * @param {...any} args * @example * HOperators.or(true, false, false) // true */ static or = or; /** * it returns the opposite of the argument given * @memberof HOperators * @param {any} arg * @example * HOperators.not(true) // false * HOperators.not(false) // true */ static not = not; /** * This method is used to compare two values if they are truly equal * @memberof HOperators * @param {any} value1 * @param {any} value2 * @example * HOperators.is(1, 1) // true * HOperators.is("hello", "hi") // false * * // Objects are compared by their keys recursively * const obj1 = {name: "john", age: 20}; * const obj2 = {name: "john", age: 20}; * HOperators.is(obj1, obj2) // true * * // Functions are compared by their source code * const fn1 = () => console.log("hello"); * const fn2 = () => console.log("hi"); * HOperators.is(fn1, fn2) // false * * // Dates are compared by their millisecond representation * const date1 = new Date(); * const date2 = new Date(date1.getTime()); * HOperators.is(date1, date2) // true * * // Regular expressions are compared by their source code * const reg1 = /hello/; * const reg2 = /hi/; * HOperators.is(reg1, reg2) // false */ static is = is; /** * loops through the given iterations and calls the callback function with the index ```i``` as argument * @memberof HOperators * @param {number} iterations// the number of iterations to loop through * @param {CallableFunction} callback // the function to call in each iteration with the `index` ```i``` as argument * @param {number} i // the starting index by default it's 0 * @param {number} step // the step to increment the index by default it's 1 * @example * HOperators.loop(5, i=>console.log(i)) // 0 1 2 3 4 */ static loop = loop; /** * loops through the given `object` and calls the `callback` function with the `key` as argument * @memberof HOperators * @param {object} obj // the object to loop through * @param {CallableFunction} callback // the function to call in each iteration with the `key` as argument * @example * const obj = {name:"ahmed", age: 20}; * HOperators.objloop(obj, (key, val) => console.log(key, val)) * // name ahmed # the keys * // age 20 # the values */ static objloop = objloop; /** * The `keyloop` function loops through the given `object` and calls the `callback` function with the `key` as argument * @param {object} obj // the object to loop through * @param {CallableFunction} cb // the function to call in each iteration with the `key` as argument * @example * const obj = {name:"ahmed", age: 20}; * keyloop(obj, key => console.log(key)) // name */ static keyloop = keyloop; /** * The `valloop` function loops through the given `object` and calls the `callback` function with the `value` as argument * @memberof HOperators * @param {object} obj // the object to loop through * @param {CallableFunction} cb // the function to call in each iteration with the `value` as argument * @example * const obj = {name:"ahmed", age: 20}; * valloop(obj, val => console.log(val)) // ahmed */ static valloop = valloop; } //// ------------------------------- HANDY HASHMAP © Handy-JS 5m/27d/23y ------------------------------- /** * HashMap implementation in JavaScript */ class HashMap { map = new Map(); constructor(obj) { this.map = new Map(); if (obj) { Object.keys(obj).forEach((key) => { this.map.set(key, obj[key]); }); } } /** * Add a key-value pair to the HashMap * @param key The key of the key-value pair * @param value The value of the key-value pair */ put(key, value) { this.map.set(key, value); } /** * Get the value associated with a key * @param key The key whose value is to be returned */ get(key) { return this.map.get(key); } /** * Get the value associated with a key or insert a new key-value pair if the key does not exist * @param key The key whose value is to be updated * @param value The value to be inserted if the key does not exist */ upsert(key, value) { if (this.contains(key)) { this.map.set(key, value); } else { this.put(key, value); } } /** * Update the value associated with a key * @param key The key whose value is to be updated * @param value The value to be updated */ update(key, value) { if (this.contains(key)) { this.map.set(key, value); } else { throw new Error(`Key ${key} does not exist`); } } /** * Remove a key-value pair from the HashMap * @param key The key whose value is to be removed */ remove(key) { this.map.delete(key); } /** * Check if the HashMap contains a given key * @param key The key to be checked */ contains(key) { return this.map.has(key); } /** * Get all the keys present in the HashMap */ keys() { return Array.from(this.map.keys()); } /** * Get all the values present in the HashMap */ values() { return Array.from(this.map.values()); } /** * Get the size of the HashMap */ size() { return this.map.size; } /** * Clear the HashMap */ clear() { this.map.clear(); } /** * Check if the HashMap is empty */ isEmpty() { return this.map.size === 0; } /** * Iterate over the HashMap */ forEach(callback) { for (const [key, value] of this.map) { callback(value, key); } } /** * Filter the HashMap */ filter(callback) { const filtered = new HashMap(); this.forEach((value, key) => { if (callback(value, key)) { filtered.put(key, value); } }); return filtered; } /** * Get the entries of the HashMap */ entries() { return Array.from(this.map.entries()); } /** * Convert the HashMap to an object */ toObject() { const obj = {}; this.forEach((value, key) => { obj[key] = value; }); return obj; } /** * Convert the HashMap to an array */ toArray() { const arr = []; this.forEach((value, key) => { arr.push([key, value]); }); return arr; } /** * Convert the HashMap to a flat array */ toFlatArray() { const arr = []; this.forEach((value, key) => { arr.push(key); arr.push(value); }); return arr; } /** * get the first key of the associated value * @param value The value whose key is to be returned */ getKeyByValue(value) { for (const [key, val] of this.map) { if (val === value) { return key; } } return null; } /** * get all the keys of the associated value * @param value The value whose keys are to be returned */ getKeysByValue(value) { const keys = []; for (const [key, val] of this.map) { if (val === value) { keys.push(key); } } return keys; } /** * update the key of a value * @param value The value whose key is to be updated * @param newKey The new key to be updated */ updateKeyByValue(value, newKey) { const key = this.getKeyByValue(value); if (key) { this.remove(key); this.put(newKey, value); } } } //// ------------------------------- HANDY MATRIX © Handy-JS 5m/28d/23y ------------------------------- /** * implementation of `matrix` operations in typescript/javascript */ class Matrix { rows; cols; data; constructor(data) { if (Array.isArray(data)) { // Copy the data array this.data = [...data]; // Check if all rows have the same number of columns const cols = data[0].length; if (!data.every((row) => row.length === cols)) { throw new Error("All rows must have the same number of columns."); } this.rows = data.length; this.cols = cols; } else { throw new Error("Invalid data format. Expecting an array of arrays."); } } /** * fill the matrix with zeros `0` based on the given `rows` and `columns` */ static zeros(rows, cols) { const data = new Array(rows) .fill(0) .map(() => new Array(cols).fill(0)); return new Matrix(data); } /** * fill the matrix with ones `1` based on the given `rows` and `columns` */ static ones(rows, cols) { const data = new Array(rows) .fill(0) .map(() => new Array(cols).fill(1)); return new Matrix(data); } /** * return a matrix with 1 along the `diagonal` and 0 elsewhere, based on the given `size` */ static eye(size) { const data = new Array(size).fill(0).map((_, i) => { const row = new Array(size).fill(0); row[i] = 1; return row; }); return new Matrix(data); } /** * return a matrix with random values between `min` and `max` based on the given `rows` and `columns` */ static random(rows, cols, max, min = 0) { const data = new Array(rows) .fill(0) .map(() => new Array(cols).fill(0).map(() => Math.randomInt(max, min))); return new Matrix(data); } /** * add 2 matrices, `matrix1` + `matrix2` */ static add(matrix1, matrix2) { if (!Matrix.isSameSize(matrix1, matrix2)) { throw new Error("Matrix dimensions must be the same for addition."); } const result = matrix1.data.map((row, i) => row.map((val, j) => val + matrix2.data[i][j])); return new Matrix(result); } /** * subtract 2 matrices, `matrix1` - `matrix2` */ static subtract(matrix1, matrix2) { if (!Matrix.isSameSize(matrix1, matrix2)) { throw new Error("Matrix dimensions must be the same for subtraction."); } const result = matrix1.data.map((row, i) => row.map((val, j) => val - matrix2.data[i][j])); return new Matrix(result); } /** * multiply 2 matrices, `matrix1` * `matrix2`, complexity: `O(n^3)` */ static multiply(matrix1, matrix2) { if (matrix1.cols !== matrix2.rows) { throw new Error("Number of columns in Matrix 1 must match the number of rows in Matrix 2 for multiplication."); } const result = new Array(matrix1.rows) .fill(0) .map(() => new Array(matrix2.cols).fill(0)); for (let i = 0; i < matrix1.rows; i++) { for (let j = 0; j < matrix2.cols; j++) { for (let k = 0; k < matrix1.cols; k++) { result[i][j] += matrix1.data[i][k] * matrix2.data[k][j]; } } } return new Matrix(result); } /** * multiply a matrix by a scalar, `matrix` * `scalar` */ static scale(matrix, scalar) { const result = matrix.data.map((row) => row.map((val) => val * scalar)); return new Matrix(result); } /** * transpose a matrix by swapping rows and columns * @param {Matrix} matrix - matrix to transpose */ static transpose(matrix) { const result = new Array(matrix.cols) .fill(0) .map(() => new Array(matrix.rows).fill(0)); for (let i = 0; i < matrix.rows; i++) { for (let j = 0; j < matrix.cols; j++) { result[j][i] = matrix.data[i][j]; } } return new Matrix(result); } /** * compare tow matrices size */ static isSameSize(matrix1, matrix2) { return matrix1.rows === matrix2.rows && matrix1.cols === matrix2.cols; } /** * check if the index of row and column is valid */ static isValidIndex(matrix, rowIndex, colIndex) { return (rowIndex >= 0 && rowIndex < matrix.rows && colIndex >= 0 && colIndex < matrix.cols); } /** * return the size of the matrix */ size() { return { rows: this.rows, cols: this.cols }; } /** * return the shape of the matrix */ shape() { return [this.rows, this.cols]; } /** * get the value of the matrix at the given row (x-axis) and column (y-axis) (zero-indexed) * @param row {number} The x-axis of the matrix * @param col {number} The y-axis of the matrix */ get(row, col) { if (!Matrix.isValidIndex(this, row, col)) { throw new Error("Invalid row or column index."); } return this.data[row][col]; } /** * set the value of the matrix at the given row (x-axis) and column (y-axis) (zero-indexed) * @param row {number} The x-axis of the matrix * @param col {number} The y-axis of the matrix * @param value {number} The value to set at the given row and column */ set(row, col, value) { if (!Matrix.isValidIndex(this, row, col)) { throw new Error("Invalid row or column index."); } this.data[row][col] = value; } /** * convert the matrix to an array */ toArray() { return [...this.data]; } /** * convert the matrix to a flattened array */ flatten() { return this.data.flat(); } /** * make a copy of the matrix */ clone() { return new Matrix([...this.data]); } /** * Print the matrix to the `console` */ log() { console.log(this.data.map((row) => row.join(" ")).join("\n")); } } export { HOperators, HashMap, Matrix }; //# sourceMappingURL=hs.min.js.map