JavaScript array reduce start from index
Asked Answered
N

5

22

This problem has been bugging me for a while now and I can't seem to find an answer in web.

Is it possible to use Array reduce method starting from a certain index?

simple example

var studentGrades = ["John Doe", "Some School", 6, 7, 8, 7, 9, 9];

If I need to loop over only integers in studentGrades, I can do that with a simple for loop

for(var i = 2; i < studentGrades.length; i++) {
  // do stuff here ...
}

But let's say I would need get an average grade which is sum of all integers divided by integers count. If Array contained only integers, then there would be no problem using reduce.

var onlyIntegersArr = [5,2,3,4];
var averageGrade = onlyIntegersArr.reduce(function(a,b){
  return a + b;
}) / onlyIntegersArr.length;

However if I know that for whatever reasons I need to skip the first two Array elements and start from index Array[2].

So for example I would apply reduce to studentGrades, but only starting from index studentGrades[2].

Is that possible with reduce?

Thank you for solutions, I like slice approach, but I prefer not using a new method in this case.

e.g.

var average = studentGrades.reduce(function(a,b,i){
  return i >= 2 ? a+b : 0;
}) / (studentGrades.length - 2);
Nard answered 27/1, 2016 at 9:55 Comment(2)
array.slice(2).reduce(...Eryneryngo
How about if condition ?Agreeable
R
20

reduce's 3rd argument is an index, here is the fiddle

var averageGrade = onlyIntegersArr.reduce(function (a, b, c) {
    if (c >= 2) {
        return a + b;
    } else {
        return 0;
    }
});

if array has more non-numeric items after second index then check this fiddle

var studentGrades = ["John Doe", "Some School", 6, 7, 8, 7, 9, 9, "Some School"];
var averageGrade = studentGrades.reduce(function (a, b, c) {
    if (c >= 2 && !isNaN(b)) {
        return a + b;
    } else if (c >= 2) {
        return a + 0;
    } else {
        return 0;
    }
})
alert(averageGrade);
Rutherford answered 27/1, 2016 at 9:58 Comment(6)
It will fail for this: var studentGrades = ["John Doe", "Some School", 6, 7,'test'];Agreeable
@RayonDabre true, but that is not what OP is asking. Anyways, let me put a check for isNaN also if OP has asked for it.Rutherford
I will accept this solution as it fits my problem most. I don't need to use a new array method, but instead just use the index parameter in reduce method. I had somehow overlooked it.Nard
I like shorter solutions, like onlyIntegersArr.reduce((a, b, c) => (c >= 2 ? a + b : 0))Cerys
I agree, but I like this solution as it's the only one pointing out to use reduce index argument.Nard
@Cerys Thanks for the editing and making it more concise and readable.Rutherford
E
11

If you know for a fact that you want to skip the first n elements, you can use Array#slice

Using ES2015 Arrow Function

var sum = array.slice(n).reduce((a, b) => a + b);

var studentGrades = ["John Doe", "Some School", 6, 7, 8, 7, 9, 9];
var sum = studentGrades.slice(2).reduce((a, b) => a + b);

document.body.innerHTML = 'SUM is = ' + sum;

In ES5, the same code can be written using anonymous function.

var sum = array.slice(n).reduce(function(a, b) {
    return a + b;
});

var studentGrades = ["John Doe", "Some School", 6, 7, 8, 7, 9, 9];
var sum = studentGrades.slice(2).reduce(function(a, b) {
    return a + b;
});

document.body.innerHTML = 'SUM is = ' + sum;

for the case you mentioned, of only adding up numeric values, regardless of where in the array they are - you could do something like

var sum = array.reduce(function(result, v) {
    return result + (parseFloat(v) || 0);
}, 0);

var studentGrades = ["John Doe", "Some School", 6, 7, 8, 7, 9, 9];
var sum = studentGrades.reduce(function(result, v) {
    return result + (parseFloat(v) || 0);
}, 0);

document.body.innerHTML = 'SUM is = ' + sum;
Eryneryngo answered 27/1, 2016 at 10:1 Comment(2)
@fast, yes, it does, a problem for sure if you have billions of elementsEryneryngo
kudos to @Cerys for the hard work he put in to editing the answer to make it look and read so goodEryneryngo
P
0

If you're sure you always need only index 2 onwards, then this is sufficient

var onlyIntegersArr = studentGrades.slice(2);
var averageGrade = onlyIntegersArr.reduce(function(a,b){
    return a + b;
}) / onlyIntegersArr.length;

If, however, you want to get all integers, then you need to filter the array

var onlyIntegersArr = studentGrades.filter(function(val) {
    return (val === parseInt(val, 10));
});
var averageGrade = onlyIntegersArr.reduce(function(a,b){
    return a + b;
}) / onlyIntegersArr.length;
Prestige answered 27/1, 2016 at 10:1 Comment(0)
O
0

Why do you overcomplicate things? Why not:

function avg(arr)
{
     var sum = 0;
     var l = 0;
     for(var i = 0; i < arr.length; i++)
     {
        if(isNaN(1*arr[i])) continue;
        sum += arr[i];
        l++;
     }
     return sum/l;
}

Maybe you need to think about keeping the data in object, where all the grades are in a separate array. And other data be in properties. You can serialize it from the array you have, and then work with the object.

Overdraw answered 27/1, 2016 at 10:9 Comment(0)
F
0

Thanks for all the replies. I have re-written the code so I have a completed working version of what I am trying to achieve.

My code looks a little long winded and just wondered if there is a cleaner and quicker version to do mark this up.

student         = [];
student[0]  = {};
student[0].grades   = [2,8,10,12,14,5];
student[0].total    = 0;

student[1]  = {};
student[1].grades   = [0,11,4,3,9];
student[1].total    = 0;

student[2]  = {};
student[2].grades   = [3,15,1,5,9];
student[2].total    = 0;

student[3]  = {};
student[3].grades = [2,10, 12, 1];
student[3].total    = 0;

for(n=0; n<student.length; n++){
  totalGrades = 0;
  /* Check if .grades matches the criteria */
  if(student[n].grades[0]!=0 && student[n].grades[0]<10){
    totalGrades = totalGrades + student[n].grades[0];
  };
  
    a1 = student[n].grades.slice(1);
  
  for(a=0; a<a1.length; a++){
    if(a1[a]<10){
        /* Add grades less than 10 */
        totalGrades = totalGrades + a1[a];
    };
  };
  
  console.log("Student: "+n+"] "+a1+"   :: Total "+totalGrades+" Original in tact: "+student[n].grades+"<br/>");
  
};
Fitts answered 1/7, 2024 at 16:28 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.