loading...

JavaScript challenge

paulwvnjohi profile image Paul Wanjohi ・1 min read

I came across a challenge you are needed to write a function that returns the sum of all even numbers from an array this is what I came up with, I feel there would be a better way to tackle that, what changes should I make?

Discussion

pic
Editor guide
Collapse
aspittel profile image
Ali Spittel

The most computationally efficient way to do this would be one loop + no higher order methods. I also like the one-liner for code elegance! Just depends on what you want to optimize!

function sumOfEven(arr) {
  let finalSum = 0
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] % 2 == 0) finalSum += arr[i]
  }
  return finalSum
}

Here's another one-liner option too that requires one HOF instead of two.

const sumEvenNumbers = arr => arr.reduce((currentSum, num) => num % 2 == 0 ? num + currentSum : currentSum)
Collapse
rhymes profile image
rhymes

Hi Paul, I think yours is reducing too many times, because you call reduce everytime there's an iteration in the first array.

This is a possible alternative:

const sumEvenNumbers = (numbers) => {
  const sum = numbers.reduce((accumulator, currentValue) => {
    if (currentValue % 2 === 0) {
      return accumulator + currentValue;
    } else {
      // return the last partial sum
      return accumulator;
    }
  }, 0);

  return sum;
}

console.log(sumEvenNumbers([9, 7, 5, 10, 12, 7, 8]));
// => 30

The sumEvenNumbers accepts a list of numbers, uses reduce (which already iterates on the numbers) and return the sum of the accumulated value and the current one if the value is even, otherwise it just return the accumulator ready for the next in line. In the end it returns the sum.

Collapse
abdulbasit313 profile image
Abdul Basit

Hope this might help.

function sumOfEven(arr) {
    const evens = arr.filter((num => num % 2 === 0)) //return all the even numbers in array
    console.log('even', evens)

    const sum = (accu, curr) => accu + curr //return sum of array
    console.log('sum', evens.reduce(sum))

    return evens.reduce(sum)
}


let arr = [1, 2, 3, 4, 5, 7, 8]

sumOfEven(arr)

Here is the one liner

function sumOfEven(arr) {
    return arr.filter((num => num % 2 === 0)).reduce((accu, curr) => accu + curr, 0)
}

sumOfEven([1, 4, 3, 4, 5, 7, 14])
Collapse
paulwvnjohi profile image
Paul Wanjohi Author

yes it has, thanks so much

Collapse
bugb profile image
bugb

Here is my solution:

  • Give a=[9,7,5,10,12,7,8]

  • Solution 1: a.reduce((m,n)=>m+!(n%2)*n,0)
    You can omit 0 like this: a.reduce((m,n)=>m+!(n%2)*n) if your array has more than 1 element.

  • Solution 2: eval(a.filter(v=>!(v%2)).join('+')).

Collapse
flynnham profile image
Flynn Buckingham

Here is both a functional and imperative example. The functional example is typically preferred, since it's readable, declarative, and the use of a prototype method enforces its use on Arrays (or anything that extends Array).

The imperative example shows an reasonably performant method. When working on substantially large arrays, this function would yield the most performance overtime compared to the functional example.

// readable example
// this is what most code you write should resemble, as it's 
// more maintainable than imperative examples. Also, this
// limits the call to types with `reduce`, so it can't be easily
// used incorrectly.
const readableSumOfEvenNumbers = array => array
    .reduce((currentSum, currentValue) => {
        // if number is not even then ignore
        if (currentValue % 2 != 0) return currentSum;
        // otherwise add to the SUM
        return currentSum + currentValue;
    }, 0);


// imperative example, single loop instead of chained calls
// good when performance is preferred over readability.
// Not needed/wanted in most cases
function perfSumOfEvenNumbers(array) {
    // keep mutable variables in higher scope
    // note that we are only bound by the length of the parameter.
    // this means we can also use this on non-reducable types, but
    // also means we need to be more careful about what we pass as an argument
    let finalSum = 0, index = array.length, valueAtIndex;
    while (index--) {
        valueAtIndex = array[index];
        if (valueAtIndex % 2 == 0) {
            finalSum += valueAtIndex;
        }
    }
    return finalSum;
}

const mixedArray = [2,3,5,6,9,10]; // even should sum to 18

console.log(readableSumOfEvenNumbers(mixedArray)); // 18
console.log(perfSumOfEvenNumbers(mixedArray)); // 18
Collapse
dionakra profile image
David de los Santos Boix

A slightly more concise one-liner. Just using the unitary operator of the sum and the multiplication, avoiding if statements or ternary operators.

const sumEvenNumbers = arr => arr.reduce((currentSum, num) => currentSum + num*(num%2))

PS: It seems to be slightly faster than the original one, but not important at all. jsperf.com/sumevennumbers/1

Collapse
jckuhl profile image
Jonathan Kuhl

It can be done with a single reduce. Pack it all into one line like a shmuck for giggles:

function sumOfEven(array) {
    return array.reduce((accum, current)=> accum + (current % 2 === 0 ? current : 0), 0);
}

Basically, it says "add to the current, if the current is even, else add zero and start at zero." It is necessary for it to start at zero or it will start with the first number in the array whether it is even or odd.

Collapse
ahmaddeel profile image
AhmadDeel

I think I would use array1.filter(n=>n%2===0).reduce((sum,num)=>sum+num,0)
I love one line codes.
Update I guess n%2===0 is not !n%2

Collapse
ahmaddeel profile image
AhmadDeel

The code from my phone !
WoW where's the uploaded image ?