1

This is my array:

var input = [
    {
        date: '2017-07-19',
        number: 10
    },
    {
        date: '2017-07-20',
        number: 7.5
    },
    {
        date: '2017-07-20',
        number: 9
    },
    {
        date: '2017-07-21',
        number: 8
    },
    {
        date: '2017-07-22',
        number: 9.3
    },
    {
        date: '2017-07-22',
        number: 6
    },
    {
        date: '2017-07-23',
        number: 5.8
    },
    {
        date: '2017-07-23',
        number: 7.2
    },
    {
        date: '2017-07-24',
        number: 9
    }
];

And this is what I would like to accomplish

 var output = [
    {
        date: '2017-07-19',
        number: [10],
        average: 10
    },
    {
        date: '2017-07-20',
        number: [10, 7.5, 9],
        average: 8.8
    },
    {
        date: '2017-07-21',
        number: [10, 7.5, 9, 8],
        average: 8.6
    },
    {
        date: '2017-07-22',
        number: [10, 7.5, 9, 8, 9.3, 6],
        average: 8.3
    },
    {
        date: '2017-07-23',
        number: [10, 7.5, 9, 8, 9.3, 6, 5.8, 7.2],
        average: 7.9
    },
    {
        date: '2017-07-23',
        number: [10, 7.5, 9, 8, 9.3, 6, 5.8, 7.2, 9],
        average: 7.9
    }
];

So far I can only add the numbers with the same dates and calculate the average of the numbers.

var temp = {};
var obj = null;
for (i = 0; i < input.length; i++) {
    obj = input[i];
    if (!temp[obj.date]) {
        temp[obj.date] = obj;
    } else {
        temp[obj.date].number += obj.number;
    }
}
var counter = {};
for (i = 0; i < input.length; i += 1) {
    counter[input[i].date] = (counter[input[i].date] || 0) + 1;
}
for (var key in counter) {
    if (counter[key] > 1) {
    }
}
var out = [];
for (var date in temp)
    out.push(temp[date]);
var finalOutput = [];
for (i = 0; i < out.length; i++) {
    finalOutput.push({
        date: out[i].date,
        mean: Math.round(out[i].number / counter[out[i].date] * 10) / 10
    });
}
console.log(finalOutput);

But I do not know how to make the var output array. Thanks so much for your help!

2
  • I'm confused what is mean ? Commented Apr 27, 2017 at 0:32
  • The average of the numbers. I just edited the question. Commented Apr 27, 2017 at 0:38

2 Answers 2

1

function group(arr) {
    // FIRST PART: group the objects and sum their numbers
    var indexHash = {};                           // helps us check whether or not a date is encountered and at which index the object for that date is stored
    var output = arr.reduce(function(acc, o) {    // for each object o in the array
        var ind = indexHash[o.date];              // get the index for this date from the index hash (if any)
        if(ind) {                                 // if there is (there is already an object fro this date)
            acc[ind].number.push(o.number);       // then push this object's number to its array of numbers
            acc[ind].mean += o.number;            // add this object's number to it's mean (mean will serve as a sum for later when we will divide it by the length)
        }
        else                                      // otherwise (if we haven't store an object for this particular date) 
            indexHash[o.date] = acc.push({        // ... then store one
                "date": o.date,                   // that has its date equal to this object's date
                "number": [o.number],             // and that has its number array containing this object's number
                "mean": o.number                  // and that has its mean initialized with this object's number
            }) - 1;
        return acc;
    }, []);
    
    // SECOND PART: sort the array by date (if not necessary then remove this bit of code)
    output.sort(function(a, b) {
        a = new Date(a.date).getTime();       
        b = new Date(b.date).getTime();
        return a - b;
    });
    
    // THIRD PART: add the numbers of previous dates to the current date
    var first = output.shift(), last = first;     // remove the first item of the array and store it (so we can get it back into the array later) and use it as the last seen object
    output.forEach(function(o) {                  // then for each object o
        o.number = last.number.concat(o.number);  // concat the last seen object's numbers to this object's number
        o.mean += last.mean;                      // add the sum of the last seen object's numbers to this object's sum
        last = o;                                 // mark this object as the last seen object (so to add its numbers to the next object)
    });
    output.unshift(first);                        // get back the first object (previously removed) to the array
    
    // FORTH PART: calculate the mean
    output.forEach(function(o) {
        o.mean /= o.number.length;                // the mean property of each object represents the sum of its number, to get the actual mean we have to divide the sum by the length of the number array
    });
    
    return output;
}


var input = [{"date":"2017-07-19","number":10},{"date":"2017-07-20","number":7.5},{"date":"2017-07-20","number":9},{"date":"2017-07-21","number":8},{"date":"2017-07-22","number":9.3},{"date":"2017-07-22","number":6},{"date":"2017-07-23","number":5.8},{"date":"2017-07-23","number":7.2},{"date":"2017-07-24","number":9}];

console.log(group(input));

Sign up to request clarification or add additional context in comments.

3 Comments

Hi Ibrahim! Thanks so much for your answer! But I would like to include all the previous numbers in the next object, for example ` { date: '2017-07-19', number: [10], average: 10 }, { date: '2017-07-20', number: [10, 7.5, 9], average: 8.8 }, { date: '2017-07-21', number: [10, 7.5, 9, 8], average: 8.6 }`, etc.
@Vic Yeah! I've just noticed! I'll edit in a moment.
What an outstanding solution!!! You are amazing! I need so much to learn! Thanks so much!!!
0

The following should work:

function mean(numbers) {
  var sum = numbers.reduce(function(a, b) { return a + b; });
  return sum/numbers.length;
}

// Sort the input array by date
input.sort(function(a, b) {
            return new Date(a.date) - new Date(b.date);
            });

// Add the first data-point to the output array
var output = [{  date: input[0].date,
                 number: [input[0].number] }];

// Loop through the remaining input array elements
for (var i=1; i<input.length; i++) {

  var lastDate = output[output.length-1];

  if (input[i].date != lastDate.date) {
    // This is a new date
    // Calculate the average for the old date
    lastDate.average = mean(lastDate.number);

    // And create an output entry for the new date
    output.push( { date: input[i].date,
                   number: lastDate.number.concat([input[i].number]) });
    // Set the number array to the previous date's number array with the newest number concatenated onto it
    
  } else {
    // If there is already an output entry for this date, then just add the new number
    lastDate.number.push(input[i].number);
  }
}

// Calculate average for last date
lastDate = output[output.length-1];
lastDate.average = mean(lastDate.number);

console.log(output);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.