Dismiss
Announcing Stack Overflow Documentation

We started with Q&A. Technical documentation is next, and we need your help.

Whether you're a beginner or an experienced developer, you can contribute.

Sign up and start helping → Learn more about Documentation →

For some reason I'm stumbling to get the result I need with Javascript arrays.

I have rows of data which contain day, and several timestamps per row. What I need to do is transform that data to an array for chart.js, but merging rows by week, and summing the hours (from the timestamps). Below is where I am creating a new array from the query result, but am struggling to get it how I need it.

Here's where I create the array (with processing):

function chartData(queryrowlist){
  var weeks = [];
  angular.forEach(queryrowlist, function(value, key) 
  {
    weeks.push(moment(value.date).format('w'),getOnHours(value),getOffHours(value))
  });
  // create chart array ...
  return chart;
}

The weeks array ends up like this:

["23",28800000,3600000,"23",30300000,2700000,"24",35400000,3300000,"24",30000000,3300000]

Which is Week Number, OnHours, OffHours

The Week Number will be used as the Label, and the Hours as the On/Off Data in angular-chart/chart.js. The problem is all of the Week Numbers have to be Unique, and all of the Hours Summed up for each week.

So, I will need to output an array like this:

chart['weeks']=["23","24"]
chart['hours']=[[59100000,6300000],[65400000,6300000]]

This is probably simple, and it's just me hitting a thought wall... but if anyone has a solution, I'd be grateful.

Thank you in advance.

Update:

For anyone who might refer to this, the resulting array is incorrect for chart.js. Answers below are correct... as asked, I just asked the wrong thing and only realized after. Feeling like a fool :/

Chart.js want's all the line values in the same array, so instead of above example which is:

chart['weeks']=["23","24"]
chart['hours']=[[onhours,offhours],[onhours,offhours]]

It should be:

chart['weeks']=["23","24"]
chart['hours']=[[onhours,onhours],[offhours,offhours]]

Update 2

To add further clarification:

For each label, there should be a value. If you have 3 labels, you should have 3 values. In my case, there's 2 sets of value arrays, and that's because I have 2 series (2 lines), 1 for On Hours, 1 for Off Hours. So here's a complete list of arrays.

chart['labels']=["23","24","25"] // strings
chart['data']=[[onhours,onhours,onhours],[offhours,offhours,offhours]] // integers
chart['series']=['On Hours','Off Hours'] // strings

If I only needed 1 line:

chart['labels']=["23","24","25","26"] // strings
chart['data']=[[onhours,onhours,onhours,onhours]] // integers, notice [ [  ] ]
chart['series']=['On Hours'] // strings

Hope that helps!

share|improve this question
    
Could you expand on the example? e.g. if you have chart['weeks'] = ["23", "24", "25"], should you also then have chart['hours'] = [[onhours,onhours,onhours], [offhours,offhours,offhours]]? – Hopeful Llama Jun 22 at 9:01
    
@HopefulLlama - Yes, that is correct. I've updated the examples. Hope that is more clear now. – Chris Jun 22 at 17:10
    
I don't know if you needed, but I've updated my answer. – Hopeful Llama Jun 22 at 21:34
up vote 2 down vote accepted

Why not split into two arrays like you wanted?

function chartData(queryrowlist){
    // Set up our data store + return object
    var chart = {
        weeks: [],
        hours: []
    };
    // For every value in the parameter given
    angular.forEach(queryrowlist, function(value, key) {
        // Get the week, and check if it is in the array
        var week = moment(value.date).format('w');
        var weekIndex = chart.weeks.indexOf(week);

        // If the index is -1, it is not in the array, so just push values;
        if(weekIndex === -1) {
            chart.weeks.push(week);
            chart.hours.push([getOnHours(value),getOffHours(value)]);
        } else {

            // If the index is not, we assume that the weekIndex is the correct index to sum the values on.
            chart.hours[weekIndex] = [chart.hours[weekIndex][0] + getOnHours(value), chart.hours[weekIndex][1] + getOffHours(value)];
        }

    });
    return chart;
}

EDIT: New answer to reflect edit to question.

The algorithm will mostly stay the same, but the output array will change slightly.

function chartData(queryrowlist){
    // Set up our data store + return object
    var chart = {
        weeks: [],
        // Notice, two arrays in array
        hours: [
            [],
            []
        ]
    };
    // For every value in the parameter given
    angular.forEach(queryrowlist, function(value, key) {
        // Get the week, and check if it is in the array
        var week = moment(value.date).format('w');
        var weekIndex = chart.weeks.indexOf(week);

        // If the index is -1, it is not in the array, so just push values;
        if(weekIndex === -1) {
            chart.weeks.push(week);
            chart.hours[0].push(getOnHours(value));
            chart.hours[1].push(getOffHours(value));
        } else {

            // If the index is not, we assume that the weekIndex is the correct index to sum the values on.
            // Also notice the change to output to different arrays
            chart.hours[0][weekIndex] += getOnHours(value);
            chart.hours[1][weekIndex] += getOffHours(value);
        }

    });
    return chart;
}
share|improve this answer
    
They want to do a summing operation when the same week number occurs more than once. – 4castle Jun 21 at 16:57
    
@4castle Thanks, I don't know why I didn't notice that. Edited my answer to hopefully reflect it. – Hopeful Llama Jun 21 at 17:02
    
You can streamline that else block with chart.hours[weekIndex][0] += getOnHours(value); chart.hours[weekIndex][1] += getOffHours(value);. Also remember that hours.push should push an array, so hours.push([getOnHours(value),getOffHours(value)]); – 4castle Jun 21 at 17:07
    
This was right on... works great, is arrays, and it's commented. Thank you. – Chris Jun 22 at 1:34

You could use an object for grouping and later sort the keys and build the chart object with the sums.

var array = ["23", 28800000, 3600000, "23", 30300000, 2700000, "24", 35400000, 3300000, "24", 30000000, 3300000],
    chart = {},
    data = Object.create(null);

array.reduce(function (r, a, i) {
    if (i % 3 === 0) {
        if (!data[a]) {
            data[a] = { week: a, hours: [0, 0] };
        }
        return a;
    }
    data[r].hours[i % 3 - 1] += a;
    return r;
}, undefined);

Object.keys(data).sort(function (a, b) {
    return a - b;
}).forEach(function (k) {
    chart.weeks = chart.weeks || [];
    chart.hours = chart.hours || [];
    chart.weeks.push(data[k].week)
    chart.hours.push(data[k].hours);
});

console.log(chart);

share|improve this answer
    
It might even be that a reduce would make more sense here, because it's ultimately doing a reduction operation in order to sum the values. It could make it easier to read. – 4castle Jun 21 at 17:17
    
would not work here, because i would lose this.last – Nina Scholz Jun 21 at 17:19
1  
Couldn't you give the reduction object a last field? – 4castle Jun 21 at 17:23
    
@4castle, it works as you suggested, thank you. – Nina Scholz Jun 21 at 17:27
    
Thank you for your contribution. – Chris Jun 22 at 1:36

If you didn't need to maintain arrays for chart.js, I would use an object instead.

function chartData(queryrowlist){
  var weeks = {};
  angular.forEach(queryrowlist, function(value, key) 
  {
    var week = moment(value.date).format('w');
    if(!weeks[week]){ //new week
      weeks[week] = { 
        onHours: getOnHours(value),
        offHours: getOffHours(value)
      }
    } else { //week exists 
      weeks[week].onHours += getOnHours(value);
      weeks[week].offHours += getOffHours(value);    
    }
  });
  // create chart array ...
  return chart;
}

Result: weeks = { 23: { onHours: 59100000 , offHours: 6300000 }, 24: { onHours: 65400000, offHours: 6600000 }}

And you would access it with weeks.week#.onHours or weeks[week#]['onHours'].

This will be much easier to read/follow/maintain than two separate arrays that need to be kept in sync.

share|improve this answer
    
They are exporting this to the chart.js API, so they can't modify the output format. My comment was misleading, so I've deleted it. – 4castle Jun 21 at 17:10
    
Thank you for your contribution. – Chris Jun 22 at 1:35

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.