5

I have the following data:

var foo = [
    {'MonthNo' : 03, 'CustomerTypeID' : 1 , 'TotalSales' : 45 },
    {'MonthNo' : 03, 'CustomerTypeID' : 2 , 'TotalSales' : 64 },
    {'MonthNo' : 03, 'CustomerTypeID' : 4 , 'TotalSales' : 89 },
    {'MonthNo' : 03, 'CustomerTypeID' : 5 , 'TotalSales' : 42 },
    {'MonthNo' : 04, 'CustomerTypeID' : 1 , 'TotalSales' : 66 },
    {'MonthNo' : 04, 'CustomerTypeID' : 2 , 'TotalSales' : 78 },
    {'MonthNo' : 04, 'CustomerTypeID' : 5 , 'TotalSales' : 20 },
    {'MonthNo' : 04, 'CustomerTypeID' : 6 , 'TotalSales' : 10 }
];

I want to convert this into the following

{'MonthNo' : 03, 'CustomerTypeID' : 1 , 'TotalSales' : 198 },
{'MonthNo' : 03, 'CustomerTypeID' : 5 , 'TotalSales' : 42 },
{'MonthNo' : 04, 'CustomerTypeID' : 1 , 'TotalSales' : 144 },
{'MonthNo' : 04, 'CustomerTypeID' : 5 , 'TotalSales' : 20 },
{'MonthNo' : 04, 'CustomerTypeID' : 6 , 'TotalSales' : 10 }

For each MonthNo, except for CustomerTypeID 5 & 6, I want to add up the TotalSales value. For Ex: MonthNo 03 for CustomerTypeID 1,2,4 their TotalSales value is summed up to 198.similarly for MonthNo 04, TotalSales value of CustomerTypeID 1 & 2 is added up to 144.

I tried using the reduce function

var result = foo.reduce(function(obj,item){
    // code here
},{});

However , I not able to segregate them to get the desired result.Any help would be appreciated.

4
  • 1
    @Rajesh It was actually more readable on one line. Commented Dec 20, 2016 at 7:06
  • @Scimonster Point accepted, but please reformat in 2 sections, Input and output Commented Dec 20, 2016 at 7:06
  • Your result is missing the brackets around the array. Commented Dec 20, 2016 at 7:15
  • 1
    This is not a good use of reduce. Just use an ordinary loop, and create nested objects that use MonthNo and CustomerTypeID as keys, and the value is the accumulated sales. Commented Dec 20, 2016 at 7:19

5 Answers 5

2

You could check the special cases and use a hash table for referencing the right object for counting.

var foo = [{ MonthNo: '03', CustomerTypeID: 1, TotalSales: 45 }, { MonthNo: '03', CustomerTypeID: 2, TotalSales: 64 }, { MonthNo: '03', CustomerTypeID: 4, TotalSales: 89 }, { MonthNo: '03', CustomerTypeID: 5, TotalSales: 42 }, { MonthNo: '04', CustomerTypeID: 1, TotalSales: 66 }, { MonthNo: '04', CustomerTypeID: 2, TotalSales: 78 }, { MonthNo: '04', CustomerTypeID: 5, TotalSales: 20 }, { MonthNo: '04', CustomerTypeID: 6, TotalSales: 10 }],
    result = foo.reduce(function (hash) {
        return function (r, a) {
            var cType = [5, 6].indexOf(a.CustomerTypeID) === -1 ? 1 : a.CustomerTypeID,
                key = [a.MonthNo, cType].join('|');

            if (!hash[key]) {
                hash[key] = { MonthNo: a.MonthNo, CustomerTypeID: cType, TotalSales: 0 };
                r.push(hash[key]);
            }
            hash[key].TotalSales += a.TotalSales;
            return r;
        }
    }(Object.create(null)), []);
 
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

1 Comment

@bikash A less graceful approach would be JSFiddle. Just a pointer though, you should try to sort input. That will be more consistent. Also you can try a.CustomerTypeID>=5 instead of checking in array. But yes having array will allow you to configure values.
0

You can check the existing arrays monthno and customerTypeID and add up the totalsales accordingly

check the following snippet

var foo = [{
  'MonthNo': 03,
  'CustomerTypeID': 1,
  'TotalSales': 45
}, {
  'MonthNo': 03,
  'CustomerTypeID': 2,
  'TotalSales': 64
}, {
  'MonthNo': 03,
  'CustomerTypeID': 4,
  'TotalSales': 89
}, {
  'MonthNo': 03,
  'CustomerTypeID': 5,
  'TotalSales': 42
}, {
  'MonthNo': 04,
  'CustomerTypeID': 1,
  'TotalSales': 66
}, {
  'MonthNo': 04,
  'CustomerTypeID': 2,
  'TotalSales': 78
}, {
  'MonthNo': 04,
  'CustomerTypeID': 5,
  'TotalSales': 20
}, {
  'MonthNo': 04,
  'CustomerTypeID': 6,
  'TotalSales': 10
}];
var reducedfoo = foo.reduce(function(previous, current, index) {
  var index = checkExistence(previous, current)
  if (index > -1)
    previous[index].TotalSales += current.TotalSales;
  else
    previous.push(current);
  return previous;
}, []);

function checkExistence(prev, curr) {
  var index = -1;
  Object.keys(prev).forEach(function(item) {
    if (prev[item].MonthNo === curr.MonthNo && curr.CustomerTypeID != 5 && curr.CustomerTypeID != 6)
      index = item;
  });
  return index;
}

console.log(reducedfoo);

Hope it helps

Comments

0

this may help you sorted foo array by MonthNo

var foo = [

  { 'MonthNo': 03, 'CustomerTypeID': 1, 'TotalSales': 45 },
  { 'MonthNo': 03, 'CustomerTypeID': 2, 'TotalSales': 64 },
  { 'MonthNo': 03, 'CustomerTypeID': 4, 'TotalSales': 89 },
  { 'MonthNo': 03, 'CustomerTypeID': 5, 'TotalSales': 42 },
  { 'MonthNo': 04, 'CustomerTypeID': 1, 'TotalSales': 66 },
  { 'MonthNo': 04, 'CustomerTypeID': 2, 'TotalSales': 78 },
  { 'MonthNo': 04, 'CustomerTypeID': 5, 'TotalSales': 20 },
  { 'MonthNo': 04, 'CustomerTypeID': 6, 'TotalSales': 10 }

];

var curMonth = -1, result = [], curObj;

for (var i = 0; i < foo.length; i++) {

  if (foo[i].CustomerTypeID == 6 || foo[i].CustomerTypeID == 5) {
    result.push(foo[i]);
    continue;
  } else {
    if (curMonth != foo[i].MonthNo) {
      curMonth = foo[i].MonthNo;
      curObj = {
        MonthNo: foo[i].MonthNo,
        CustomerTypeID: 1,
        TotalSales: foo[i].TotalSales
      };
      result.push(curObj);
    } else {
      curObj.TotalSales += foo[i].TotalSales;
    }

  }

}

console.log(result);

Comments

0

A two-step functional approach with reduce:

var groups = foo.reduce(function(groups,item){
  var newGroup;
  var groupId = item.MonthNo;
  if (item.CustomerTypeID === 5 || item.CustomerTypeID === 6) {
    groupId = groupId + '-' + item.CustomerTypeID;
  }
  if (!groups[groupId]) {
    groups[groupId] = [];
  }
  groups[groupId].push(item);
  return groups;
},{});

var result = Object.keys(groups).reduce(function(res, groupId) {
  var merged = groups[groupId].reduce(function(merged, item) { 
    if (!merged.MonthNo) {
        merged.MonthNo = item.MonthNo;
    }
    if (!merged.CustomerTypeID) {
        merged.CustomerTypeID = item.CustomerTypeID;
    }
    merged.TotalSales = merged.TotalSales + item.TotalSales;
    return merged;
  }, {TotalSales: 0});
  res.push(merged);
  return res;
}, []);

console.log(result);

NOTE: with ES6 this would look nicer.

Comments

0
answer={};
for(i=0;i<foo.length;i++){
elem=foo[i];
answer[elem["MonthNo"]]=answer[elem["MonthNo"]]||{};
answer[elem["MonthNo"]][elem["CustomerTypeId"]]=answer[elem["MonthNo"]][elem["CustomerTypeId"]]||0;
     answer[elem["MonthNo"]][elem["CustomerTypeId"]]+=elem["TotalSales"];
}

This will result in:

answer:{
   15 (monthNo):{
       12 (Customer type id):123(Total Sales)
     }}

Now can print (or push to an array):

for(month in answer){
 for(id in answer[month]){
   console.log(month+" "+id+":"+answer[month][id];
 }}

4 Comments

Please explain your attempt. Just adding code is not good enough
Can you make this into an executable stack snippet so we can see the results?
I don't see how this adds up the TotalSales values.
@Barmar: i was at school and where interupted by a lesson... Should work now

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.