Search code examples
javascriptunit-testingtdd

How can I get average number in an array contain string and number


I'm writing a function to pass the test that have array contains number and string.

Here is the test cases average-numner.test.js:

var average = require("./get-average");

test("Average", function() {
  var numbers = [4, "-", 8, 11, "hello", "57", 0, 2];
  var expected = 5;

  var output = average(numbers);

  expect(output).toEqual(expected);
});

Here is the function that I wrote average-number.js:

// the input is an array of numbers and strings
// return the average of all the numbers
// be sure to exclude the strings
function averageNumbers(str) {
  let sum = 0;
  let newArr = [];
  var filtered = str.filter(function(item) {
    return parseInt(item);
  });
  return filtered;
}

console.log(averageNumbers([4, "-", 8, 11, "hello", "57", 0, 2]));

//    module.exports = averageNumbers;

I achieved that I got new array with only number but it still have string "57" in my filtered array. How can I get rid of it and find sum to get average number?


Solution

  • Map and filter

    Note I changed the variable name str to arr since it is not a string.

    I test for type and whether or not the number is finite and added the rest of the calculation

    The code now returns the expected 5

    // the input is an array of numbers and strings
    // return the average of all the numbers
    // be sure to exclude the strings
    function averageNumbers(arr) {
      const filtered = arr.filter(item => typeof item === 'number' && isFinite(item))
      const sum = filtered.reduce((a,b) => a+b)
      return +parseFloat(sum/filtered.length).toPrecision(12); // this can be ugly
    }
    
    console.log(averageNumbers([4, "-", 8, 11, "hello", "57", 0, 2]));
    console.log(averageNumbers([3, "-", 4, 11, "hello", "57", 0, 2, 3]));

    Just a reduce returning an object to see the sub parts

    // the input is an array of numbers and strings
    // return the average of all the numbers
    // be sure to exclude the strings
    const averageNumbers = arr => {
      const averageObject = arr.reduce((acc,item,i) => {
        if (typeof item === 'number' && isFinite(item)) {
          acc.sum+=item;
          acc.nofItems++;
        }  
        if (i===arr.length-1) acc.average = acc.sum/acc.nofItems;
        return acc;
      },{sum:0,nofItems:0, average:0})
      return averageObject;
    }  
    
    const ave1 = averageNumbers([4, "-", 8, 11, "hello", "57", 0, 2]);
    console.log(`Average of ${ave1.nofItems} numeric items was ${ave1.average}. The sum was ${ave1.sum}`) 
    const ave2 = averageNumbers([3, "-", 4, 11, "hello", "57", 0, 2, 3]);
    console.log(`Average of ${ave2.nofItems} numeric items was ${ave2.average}. The sum was ${ave2.sum}`)