fuzzybabybunny
fuzzybabybunny

Reputation: 5254

Javascript Return Array of Average Test Results Based on Date

Say that I've got this array:

testResults = [
    {
        dateCreated: "2014-07-12",
        score: 27.1
    },
    {
        dateCreated: "2014-05-11",
        score: 99.3,
    },
    {
        dateCreated: "2014-07-22",
        score: 88.8
    },
    {
        dateCreated: "2014-07-01",
        score: 33.3
    }
];

I want to create a function that:

takes testResults, startDate, endDate, and interval as arguments and calculates the average test results and returns an array as a result:

calculateTestAverages(testResults, "2014-04-01", "2014-07-30", "month");

would return

testAverages = [0, 99.3, 0, 49.7]

I think for now I want to just create an intermediary 2-D array:

intermediaryArray = [ [0], [99.3], [0], [27.1, 88.8, 33.3] ]

because calculating the average on this intermediary array will be easy.

What I've got so far does NOT work:

// takes a string date and converts it into a Date object.
var convertToDateObject = function(date){
    dateObject = new Date(date);
    return dateObject;
}

// takes a string date and returns the month.
var getMonth = function(date){
    return convertToDateObject(date).getMonth();
}

var calculateTestAverages = function(testResults, startDate, endDate, interval){

    var intermediaryArray = [];

    if( interval == "month" ){

        startingMonth = getMonth(startDate);
        endingMonth = getMonth(endDate);
        maxArrayIndex = endingMonth - startingMonth;

        for (var i = 0; i <= maxArrayIndex; i++){
            intermediaryArray[i] = [];
            for (var month = startingMonth; month <= endingMonth; month++){
                for (var testNumber = 0; testNumber < testResults.length; testNumber++){
                    if ( getMonth(testResults[testNumber].dateCreated) == month ){
                        intermediaryArray[i].push(testResults[testNumber].score);
                    };
                };
            };
        };
    };

    return intermediaryArray;

}

I've been stuck on this thing for hours. I think my brain is kinda fried at this point.

Upvotes: 1

Views: 171

Answers (1)

Vivek Pradhan
Vivek Pradhan

Reputation: 4847

I will answer your question first and then explain what went wrong. Don't worry about it, the logic behind your code is absolutely fine. It's just a misplaced curly brace i.e. }.

Let's look at your nested for loops and see how they proceed:

 var intermediaryArray = []; //initialized earlier

 ...

 for (var i = 0; i <= maxArrayIndex; i++){
        intermediaryArray[i] = [];
        for (var month = startingMonth; month <= endingMonth; month++){
            for (var testNumber = 0; testNumber < testResults.length; testNumber++){
                if ( getMonth(testResults[testNumber].dateCreated) == month ){
                    intermediaryArray[i].push(testResults[testNumber].score);
                };
            };
        };
    };

In the test case that you provide, length of the intermediaryArray is 4 which gets calculated perfectly. The outer-most for loop runs four times. And for every iteration, you do this part:

  for (var month = startingMonth; month <= endingMonth; month++){
        for (var testNumber = 0; testNumber < testResults.length; testNumber++){
            if ( getMonth(testResults[testNumber].dateCreated) == month ){
                intermediaryArray[i].push(testResults[testNumber].score);
            };
        };
    };

The code above basically loops from startingMonth to endingMonth and finds the appropriate elements of testResulsts array in that month and is supposed to push it to the intermediaryArray.

In essence, there should be one entry for a specific month that represents an index in intermediaryArray. However, in your for loop for every index of intermediaryArray, you do this check against all the months. Let's do a dry run for i = 0:

 i = 0
 ----------- 
 startingMonth = 4,
 endingMonth = 7

 month = 4 : Nothing gets pushed into intermediaryArray[0]
 month = 5 : {dateCreated: "05/11/2014",score: 99.3} gets pushed into intermediaryArray[0]
 month = 6 : Nothing gets pushed
 month = 7 : The remaining 3 tests get pushed into intermediaryArray[0]

Ultimately all the results get pushed into intermediaryArray[0] as we did not change i with the month variable

This is the reason why you in your final returned intermediaryArray, you had all the testResults pushed at the end of all the loops.

The workaround is really simple, you initialize the intermediaryArray once and then populate the intermediaryArray[i] i.e. push to it new elements every month. In other words, you loop through the intermediaryArray in the for loop where you loop through the months because there is a one-one correspondence between the elements.

Something like this would suffice :

 for (var i = 0; i <= maxArrayIndex; i++){
        intermediaryArray[i] = [];  //Initialize the empty array here based on the size
     };

 for (var month = startingMonth,i=0; month <= endingMonth; month++,i++){
 //Simply update the value of i when you update the value of month. 
 //You don't have to enclose the whole thing into the loop that initialises intermediaryArray

       for (var testNumber = 0; testNumber < testResults.length; testNumber++){
                if ( getMonth(testResults[testNumber].dateCreated) == month ){
                    intermediaryArray[i].push(testResults[testNumber].score);
                };
       };
  };

It's good to plan on the constraints that we enforce on for loops before coding them. Once you know how the arrays are traversed and the way you store it, it's simply about plugging the right conditions into the for loop. Hope it clarifies things and helps you get started in the right direction.

Upvotes: 2

Related Questions