JavaScript Refactor From Two to Many Function Arguments

149 Views Asked by At

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()
}
1

There are 1 best solutions below

14
On BEST ANSWER

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;
});