JavaScript Refactor From Two to Many Function Arguments - javascript

These two JavaScript functions each accept TWO array arguments and return ONE array result. Conforming to ES3, how can I rewrite these to accept an indefinite number of array inputs?
function sum(v, w) {
for (var a = jsArray(v), b = jsArray(w), t = 0; t < a.length; t++) a[t] += b[t];
return vbArray(a);
}
function mul(v, w) {
for (var a = jsArray(v), b = jsArray(w), t = 0; t < a.length; t++) a[t] *= b[t];
return vbArray(a);
}
The odd jsArray() function is required because the arrays to be processed are coming from VBA and jsArray() converts them to JavaScript arrays:
function jsArray(v) {
return new VBArray(v).toArray()
}

You can try to use array-like object arguments in order to get all passed arguments:
function someFunc() {
for (var i=0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
someFunc('a', 'b', 'c');
Example of transformed sum function. Beware that this works if all the passed arrays have the same length.
function sum() {
var arrays = [];
for (var i = 0; i < arguments.length; i++) {
arrays[i] = jsArray(arguments[i]);
}
for (var j = 1; j < arrays.length; j++) {
for (var t = 0; t < arrays[0].length; t++) {
arrays[0][t] += arrays[j][t];
}
}
return vbArray(arrays[0]);
}
Generalized solution:
function process(concreteFunc) {
var arrays = [];
for (var i = 1; i < arguments.length; i++) {
arrays.push(jsArray(arguments[i]));
}
for (var j = 1; j < arrays.length; j++) {
for (var t = 0; t < arrays[0].length; t++) {
arrays[0][t] = concreteFunc(arrays[0][t], arrays[j][t]);
}
}
return vbArray(arrays[0]);
}
var sum = process.bind(null, function (a, b) {return a + b});
var mul = process.bind(null, function (a, b) {return a * b});
Solution without .bind:
function process(concreteFunc, args) {
var arrays = [];
for (var i = 0; i < args.length; i++) {
arrays.push(jsArray(args[i]));
}
for (var j = 1; j < arrays.length; j++) {
for (var t = 0; t < arrays[0].length; t++) {
arrays[0][t] = concreteFunc(arrays[0][t], arrays[j][t]);
}
}
return vbArray(arrays[0]);
}
function createFunc(handler) {
return function() {
return process(handler, Array.prototype.slice.call(arguments));
}
}
var sum = createFunc(function (a, b) {return a + b});
var mul = createFunc(function (a, b) {return a * b});
Improved version to support ability to implement avg:
function process(concreteFunc, args) {
var arrays = [];
for (var i = 0; i < args.length; i++) {
arrays.push(jsArray(args[i]));
}
var result = [];
for (var j = 0; j < arrays[0].length; j++) {
var items = [];
for (var t = 0; t < arrays.length; t++) {
items.push(arrays[t][j]);
}
result.push(concreteFunc(items));
}
return vbArray(result);
}
function createFunc(handler) {
return function() {
return process(handler, Array.prototype.slice.call(arguments));
}
}
function reduce(items, handler) {
var result = items[0];
for (var i = 1; i < items.length; i++) {
result = handler(result, items[i]);
}
return result;
}
var sum = createFunc(function(items) {
return reduce(items, function (a, b) {return a + b});
});
var mul = createFunc(function(items) {
return reduce(items, function (a, b) {return a * b});
});
var avg = createFunc(function(items) {
return reduce(items, function (a, b) {return a + b}) / items.length;
});

Related

Is there a way to extend JavaScript call stack size?

I have tried setting Error.stackTraceLimit = Infinity in chrome and firefox, but no effect.
I'm just trying to multiply two matrixes in a recursive way.
it breakes at the point of a [32][32] matrix.
Here is the code that i run, a simple devide and conquer matrix multiplication
first i generate 2 random matrices and then multiply them
function divideConquer(a, b) {
var i = 0,
j = 0,
k = 0;
var c = [];
let row = [];
// creating the output
for (let l = 0; l < a.length; l++) {
row = [];
for (let m = 0; m < b[0].length; m++) {
row.push(parseInt(0));
}
c.push(row);
}
multiplyRecursion(a, b);
return c;
function multiplyRecursion(a, b) {
// If all rows traversed
if (i >= a.length)
return;
// If i < row1
if (j < b[0].length) {
if (k < a[0].length) {
c[i][j] += a[i][k] * b[k][j];
k++;
multiplyRecursion(a, b);
}
k = 0;
j++;
multiplyRecursion(a, b);
}
j = 0;
i++;
multiplyRecursion(a, b);
}
}
function generateRandomMatrix(n) {
let row = [],
matrix = [];
for (let i = 0; i < n; i++) {
row = [];
for (let j = 0; j < n; j++) {
row.push(Math.floor(Math.random() * 10));
}
matrix.push(row);
}
return matrix;
}
let a = generateRandomMatrix(32);
let b = generateRandomMatrix(32);
console.log(divideConquer(a, b));

How can I refactor a lot of similar nested loops in my Matrix class?

How can I properly refactor my Matrix class where nearly all the methods I use in this class have double nested loops which all look almost exactly the same?
Here are two of many methods that I wish to include in this class. It's going to be unnecessarily long if I don't find a better way to deal with this.
randomize() {
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
this.matrix[i][j] = Math.random();
}
}
}
add(n) {
if (n instanceof Matrix) {
for (let i = 0; i < this.matrix.length; i++) {
for (let j = 0; j < this.matrix[i].length; j++) {
this.matrix[i][j] += n.matrix[i][j];
}
}
} else {
for (let i = 0; i < this.matrix.length; i++) {
for (let j = 0; j < this.matrix[i].length; j++) {
this.matrix[i][j] += n;
}
}
}
}
Similar to Barmar's answer just with a different flavor:
// Specify the limits for i, j, and then pass in a function
// which takes the index parameters.
function loop(iMax, jMax, fn) {
for (let i = 0; i < iMax; i++) {
for (let j = 0; j < jMax; j++) {
fn(i, j);
}
}
}
function randomize() {
loop(this.rows, this.columns, (i, j) => {
this.matrix[i][j] = Math.random();
});
}
function add(n) {
if (n instanceof Matrix) {
loop(this.matrix.length, this.matrix[0].length, (i, j) => {
this.matrix[i][j] += n[i][j];
});
}
}
This more generic approach allows you to do whatever you want with the loop indices. You could do reassignment, or you could log out the matrix values, or assign them to a new matrix.
loop(this.rows, this.cols, (i, j) => {
console.log(this.matrix[i][j]);
});
loop(this.rows, this.cols, (i, j) => {
that.matrix = this.matrix[i][j];
});
You can use a function.
class Matrix {
constructor(arr) {
this.matrix = arr;
this.rows = arr.length;
this.cols = arr[0].length;
}
loop(func, arr2, arr2Recurse) {
this.matrix = this.matrix.map((row, i) =>
row.map((col, j) => func(col, arr2Recurse ? arr2.matrix[i][j] : arr2))
);
}
randomize() {
this.loop(() => Math.random());
}
add(n) {
this.loop((el, nEl) => (el += nEl), n, n instanceof Matrix);
}
}
var a = new Matrix([[1, 2], [3, 4]]);
var b = new Matrix([[5, 6], [7, 8]]);
a.add(b);
console.log(a);
a.add(1);
console.log(a);
a.randomize();
console.log(a);
Use a higher-order function, which receives a function to be called on each element and returns the new value to replace it.
In my example below, the callback function also receives the indexes, so it can use them to reference another matrix, which is needed in the add method.
updateEach(callback) {
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
this.matrix[i][j] = callback(this.matrix[i][j], i, j);
}
}
}
randomize() {
this.updateEach(() => Math.random());
}
add(n) {
if (n instanceof Matrix) {
this.updateEach((oldval, i, j) => oldval + n.matrix[i][j]);
} else {
this.updateEach((oldval) => oldval + n)
}
}

possible combinations get a targetTotal counting itself as a case

Trying to count possible combinations to get a targetTotal. Using powerSet returns the sum without adding itself. E.g [1,2,3,5] returns [3+1] for a targetSum of 4, whereas I expect to get [1+1+1+1], [2+2], [3+1].
Do you have any ideas how I could make it count itself first as a case?
function powerset(arr) {
var ps = [[]];
for (var i=0; i < arr.length; i++) {
for (var j = 0, len = ps.length; j < len; j++) {
ps.push(ps[j].concat(arr[i]));
}
}
return ps;
}
function sum(arr) {
var total = 0;
for (var i = 0; i < arr.length; i++)
total += arr[i];
return total
}
function findSums(numbers, targetSum) {
var sumSets = [];
var numberSets = powerset(numbers);
for (var i=0; i < numberSets.length; i++) {
var numberSet = numberSets[i];
if (sum(numberSet) == targetSum)
sumSets.push(numberSet);
}
return sumSets;
}
Example invocation:
findSums([1,2,3,4,5],6); [[2,3], [1,4], [5], [1,1,1,1,1,1], [2,2,2], [3,3]]

Arrays with elements less or equal to the elements in given array

What is the most JS-style way to solve the following problem?
Given an array A, find all arrays B, such that for i <= A.length: B[i] <= A[i]. Example of what I expect:
#Input
A = [1,2,0]
#Output
B = [[0,0,0],
[1,0,0],
[1,1,0],
[1,2,0],
[0,1,0],
[0,2,0]]
In Python I used:
B = [[]];
for t in [range(e+1) for e in A]:
B = [x+[y] for x in B for y in t]
Thanks in advance!
Use the following code (any loop for one item of the array a):
var a = [1, 2, 0], b = [];
for (var i = 0; i < a[0]; i++) {
for (var j = 0; j < a[1]; j++) {
for (var k = 0; k <= a[2]; k++) {
b.push([i, j, k]);
}
}
}
If you know the numebr of items in the array a only on runtime, use the following recursive function:
function fillArray(source, dest, recursionLevel, tempArr) {
if (recursionLevel >= source.length) {
dest.push(tempArr);
return;
}
for (var i = 0; i <= source[recursionLevel]; i++) {
var tempArr2 = tempArr.slice(); // Copy tempArr
tempArr2.push(i);
fillArray(source, dest, recursionLevel + 1, tempArr2);
}
}
fillArray(a, b, 0, []);
I found this solution. I'm sure it can be coded in a much nicer way. However, it works and I hope you find it useful
all_combinations(A){
var B = [];
for (var i = 0; i < A[0] + 1; i++) {
B.push([i]);
}
for (var i = 1; i < A.length; i++) {
var _tmp_array = [];
for (var j = 0; j < A[i] + 1; j++) {
for (var k = 0; k < B.length; k++) {
var _new_element = B[k].concat([j]);
_tmp_array.push(_new_element);
}
}
B = _tmp_array;
}
return B;
}

Combinations of n words from array of m words - Javascript

Given arr = ['mat','cat','fat']
A function getComb(arr, n = 2) where n is the number of words each combination must have.
Expected results:
mat cat
mat fat
cat fat
I could not modify the code below any further to get the desired results. Any idea? thx
Thanks to Knskan3:
'getCombinations': (arr, n) => {
let i, j, k, elem, l = arr.length, childperm, ret = [];
if (n === 1) {
for (let i = 0; i < arr.length; i++) {
ret.push([arr[i]]);
}
return ret;
}
else {
for (i = 0; i < l; i++) {
elem = arr.shift();
for (j = 0; j < elem.length; j++) {
childperm = lib.getCombinations(arr.slice(), n - 1);
for (k = 0; k < childperm.length; k++) {
ret.push([elem[j]].concat(childperm[k]));
}
}
}
return ret;
}
},
I suggest a space-efficient generator function:
// Generate all k-combinations of first n array elements:
function* combinations(array, k, n = array.length) {
if (k < 1) {
yield [];
} else {
for (let i = --k; i < n; i++) {
for (let combination of combinations(array, k, i)) {
combination.push(array[i]);
yield combination;
}
}
}
}
// Example:
console.log(...combinations(['mat', 'cat', 'fat'], 2));

Categories