-1

I solve CodeWars challenge: `Write function find_average which calculates the average of numbers in a given array. But the questions is:

1) How can this code be optimized in Big-O notation terms, is it possible to reduce loop-iterations: input values testing with array.every (need to exclude TypeError when array.reduce with [1, 2, 'string'])

2) I think now complexity equal to Θ(n), am I right?

function find_average(array) {
  // your code here
  if (Array.isArray(array) && array.every(elem => typeof elem == 'number')) {
    const numberCount = array.length;
    if (numberCount == 1) {
      return array[0];
    }
    let sum = array.reduce((accumulator, currentValue) => {
      return accumulator + currentValue;
    })
    const averageNumber = sum/numberCount;
    return averageNumber;
  }
  throw new TypeError('Array value are not number.');
}
storenth
  • 967
  • 11
  • 18
  • Just don't do `array.every`, since it iterates the entire array once. Loop the array and increment the value. If any is not numeric, just break the routine and return, otherwise continue until finished and return the average. – briosheje Aug 16 '19 at 07:33
  • First, if your code works and objective of this post is optimization/improvements, CodeReviews is the right forum. Second, please share a sample input so we can understand and help you – Rajesh Aug 16 '19 at 07:34
  • @kirill.z Please mind the tone. Second, your shared code works fine. Correct? All you are looking for is a better way to achieve it. CodeReviews is meant for that. SO is for solving problems. Nonetheless, based on your updated post, I'll reopen it. Still my suggestion is to lookup CodeReviews for such queries – Rajesh Aug 16 '19 at 08:23
  • @Rajesh It could be turned into a Code Review question, but as it currently stands, it would be closed for lacking a description of the challenge. – Mast Aug 16 '19 at 08:40
  • @Mast Write function find_average which calculates the average of numbers in a given array. – storenth Aug 16 '19 at 08:47
  • @Mast question about how this algo can be simplified through optimization, and answered by CertainPerformance – storenth Aug 16 '19 at 08:48

2 Answers2

2

There's no need to iterate twice, once to check if every element is a number, and once to add them all up. Rather, you can just iterate once, and if any element is not a number, throw immediately:

function find_average(array) {
  if (!Array.isArray(array)) {
    throw new TypeError('Array value are not number.');
  }
  const sum = array.reduce((a, b) => {
    if (typeof b !== 'number') {
      throw new TypeError('Array value are not number.');
    }
    return a + b;
  }, 0);
  return sum / array.length;
}

function find_average(array) {
  if (!Array.isArray(array)) {
    throw new TypeError('Array value are not number.');
  }
  const sum = array.reduce((a, b) => {
    if (typeof b !== 'number') {
      throw new TypeError('Array value are not number.');
    }
    return a + b;
  }, 0);
  return sum / array.length;
}

console.log(find_average([1, 2, 3]));
console.log(find_average([1, 'foo', 3]));

Both this and your original implementation have overall complexity of O(n).

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • tested reduce just work with next both tested accumulator and currValue ` let sum = array.reduce((accumulator, currentValue) => { if (typeof accumulator !== 'number') { throw new TypeError('Array value are not number.'); } else if (typeof currentValue !== 'number') { throw new TypeError('Array value are not number.'); } else return accumulator + currentValue; })` – storenth Aug 16 '19 at 08:41
  • 1
    There's no need to test if the accumulator is a number if it starts at 0 - testing only the `currentValue` (or `b`) is sufficient – CertainPerformance Aug 16 '19 at 08:43
2

You could take a single loop and check if you got an array in advance.

This is not only an O(n) approach, it faster than using array methods for iterating.

function find_average(array) {
    // your code here
    var sum = 0,
        count = 0,
        i;
  
    if (!Array.isArray(array) || !array.length) return; // or throw error

    for (i = 0; i < array.length; i++) {
        if (typeof array[i] !== 'number') continue;
        sum += array[i];
        count++;
    }
    if (count === 0) return; // or throw error
    return sum / count;
}

console.log(find_average([null, 3, 5, '10', undefined]));
console.log(find_average());
console.log(find_average([]));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Where can I find technical justification `for-loop faster than using array methods for iterating`.? Thx for reply. – storenth Aug 16 '19 at 08:40
  • 1
    you could find it out by using codewars performance logging. the main reason, `for` performs faster because it does not carry overhead like `this` or other parts for the callback. – Nina Scholz Aug 16 '19 at 08:43