0

I am trying to loop through an array of arrays with object [[{},{},{}],[{},{},{}]], and create a new array that basically "totals" the arrays. I am a bit at a loss on how to achieve this.

My data looks like this:

[
  [{
    "2017-01-05": 607
  }, {
    "2017-01-06": 430
  }, {
    "2017-01-07": 357
  }, {
    "2017-01-08": 277
  }],
  [{
    "2017-01-09": 607
  }, {
    "2017-01-10": 430
  }, {
    "2017-01-11": 357
  }, {
    "2017-01-12": 277
  }]
],

I would like to "count" and "label" each week, and total each week. Example:

newArray: [{"Week 1": 1075}, {"Week 2": 1590}]

I know I should probably use a forEach loop, but then it gets a bit sketchy:

dateArray.forEach( function (arrayWeek)
{
  // push and name etc. functionality
});

I would greatly appreciate your assistance and guidance.

Rajesh
  • 24,354
  • 5
  • 48
  • 79
onmyway
  • 1,435
  • 3
  • 29
  • 53
  • 2
    It's going to be difficult, as you need to define what constitutes a 'week', and when it begins. Otherwise, I'd suggest using reduce rather than forEach() if I get time today I'll try to get an answer up for you. – rrd Jan 12 '17 at 11:48
  • Thank you, that will be great! The way to determine the start of a week, would probably be the start of a new array. I think! :D – onmyway Jan 12 '17 at 11:54

4 Answers4

3

I would use the map function and reduce each week inside the map:

var days = [
  [{"2017-01-05":607}, {"2017-01-06":430}, {"2017-01-07":357}, {"2017-01-08":277}],
  [{"2017-01-09":607}, {"2017-01-10":430}, {"2017-01-11":357}, {"2017-01-12":277}]
];

function aggregator(memo, day) {
  for (var i in day) {
    memo += day[i];
  }
  return memo;
}

// Original version from the question
var weeks = days.map(function(week, index) {
  var obj = {};
  obj['Week ' + (index + 1)] = week.reduce(aggregator, 0);
  return obj;
});

console.log(weeks);

// Follow up version from question in the comments
var weeks2 = days.map(function(week, index) {
  return {
    name: 'week ' + (index + 1),
    total: week.reduce(aggregator, 0)
  };
});

console.log(weeks2);
rdubya
  • 2,916
  • 1
  • 16
  • 20
  • Thank you for the help! If I may ask; which of the solutions would be preferable, and why? – onmyway Jan 12 '17 at 12:10
  • 1
    Either will do what you want it to. Personally, I think mine is easier to read but that's probably the only real difference. There may be some performance differences but I doubt they would be enough to choose one over the other unless you are running this on a very large array very frequently. – rdubya Jan 12 '17 at 12:13
  • I apologize for asking this now, but how would I be able to modify your solution to change the output to look like this: `[{"name": "week 1", "total": 1595}, {"name": "week 2", "total": 2075}]` ? – onmyway Jan 12 '17 at 13:03
  • 1
    @onmyway Sorry, I didn't see this earlier. I've updated my answer to include that format. – rdubya Jan 13 '17 at 01:17
  • Thank you very much, really appreciated! – onmyway Jan 13 '17 at 05:48
2

You can try something like this.

var data=[[{"2017-01-05":607},{"2017-01-06":430},{"2017-01-07":357},{"2017-01-08":277}],[{"2017-01-09":407},{"2017-01-10":430},{"2017-01-11":357},{"2017-01-12":277}]];

var result = data.reduce(function(p, c, i) {
  var total = c.reduce(function(total, obj) {
    for (var k in obj) {
      total += obj[k];
    }
    return total;
  }, 0);
  
  // Format object in any format you want
  var tmp = {};
  tmp.name = "Week " + (i+1)
  tmp.total = total;
  
  // Push formatted object in array
  p.push(tmp)
  return p;
}, [])

console.log(result)

Note, I'd suggest you to use an object instead of array of objects. Benefit of this would be that you will not require to loop over output to get value. You can directly so result['week'+index]

var data=[[{"2017-01-05":607},{"2017-01-06":430},{"2017-01-07":357},{"2017-01-08":277}],[{"2017-01-09":407},{"2017-01-10":430},{"2017-01-11":357},{"2017-01-12":277}]];

var result = data.reduce(function(p, c, i) {
  var total = c.reduce(function(total, obj) {
    for (var k in obj) {
      total += obj[k];
    }
    return total;
  }, 0);

  p["week" + (i + 1)] = total;
  return p;
}, {})

console.log(result)
Rajesh
  • 24,354
  • 5
  • 48
  • 79
  • How would I be able to modify your solution to change the push to look like this: `{"name": "week 1", "total": 595}` ? – onmyway Jan 12 '17 at 12:59
  • 1
    @onmyway I'm pushing tmp in array. Just update this object and you are good to go – Rajesh Jan 12 '17 at 13:01
  • Thank you, I will give it a shot! – onmyway Jan 12 '17 at 13:03
  • Do I edit this line, and can you perhaps help with the dbl and single quotes *blush*? `tmp['"name": "week " + (i + 1),"total": total'];` – onmyway Jan 12 '17 at 13:20
  • Thank you very much, Rajesh! i cannot believe i hit a blank like that - I have done this before, really. :D – onmyway Jan 13 '17 at 05:51
1

the variable weeks should hold what you want... I'm assuming the week number is the actual week number in the year and not some index in the array. I'd also not use the same data structure but am adapting so that you won't need to change your structure.

var arr = [
    [{
        "2017-01-05": 607
    }, {
        "2017-01-06": 430
    }, {
        "2017-01-07": 357
    }, {
        "2017-01-08": 277
    }],
    [{
        "2017-01-09": 607
    }, {
        "2017-01-10": 430
    }, {
        "2017-01-11": 357
    }, {
        "2017-01-12": 277
    }]
]

function week(d) {
    // taken from http://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
    d.setHours(0, 0, 0, 0);
    d.setDate(d.getDate() + 4 - (d.getDay() || 7));
    return Math.ceil((((d - new Date(d.getFullYear(), 0, 1)) / 8.64e7) + 1) / 7);
}

var weeks = {};
for (var x in arr) {
    var subarr = arr[x]
    for (var y in subarr) {
        var obj = subarr[y];
        for (var when in obj) {
            var d = new Date(when);
            var which_week = "Week " + week(d);
            if (which_week in weeks) {
                weeks[which_week] += obj[when];
            } else {
                weeks[which_week] = obj[when];
            }
        }
    }
}
Amnon
  • 2,708
  • 2
  • 22
  • 21
0

without forEach

var arrs = [
  [{
    "2017-01-05": 607
  }, {
    "2017-01-06": 430
  }, {
    "2017-01-07": 357
  }, {
    "2017-01-08": 277
  }],
  [{
    "2017-01-09": 607
  }, {
    "2017-01-10": 430
  }, {
    "2017-01-11": 357
  }, {
    "2017-01-12": 277
  }]
];

function loop1(arr, i, r){
    r = (r ? r : 0) + arr[i][Object.keys(arr[i])[0]];
    return ++i == arr.length ? r : loop1(arr, i, r);
}
function loop2(arrs, i, r){
    i = i ? i : 0;
    r = r ? r : {};
    r['Week ' + (i + 1)] = loop1(arrs[i], 0);
    return ++i == arrs.length ? r : loop2(arrs, i, r);
}

var newArr = loop2(arrs);
raksa
  • 898
  • 6
  • 17