Jiji
Jiji

Reputation: 113

Sum function with javascript

Am trying to sum the number of tickets per month. the array I have:

[['tickets', 'month','year'], [1, "june",2016],[3, "june",2015],[1, "december",2015]]

The result I want :

[['year', 'june','december'], [2016,1,0],[2015,3,1]]

but I can't figure out how to do it with javascript. any help? thanks,

Upvotes: 0

Views: 144

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386520

You could use a dynamic approach for an arbitrary count of month with a hash table as reference to the years.

var data = [['tickets', 'month', 'year'], [1, "june", 2016], [3, "june", 2015], [1, "december", 2015]],
    columns = ['year', 'june', 'december'],
    temp = data.slice(1).reduce(function (result, item) {
        result[item[2]] = result[item[2]] || {};
        result[item[2]][item[1]] = item[0];
        return result;
    }, {}),
    result = Object.keys(temp).sort(function (a, b) { return b - a; }).map(function (year) {
        return columns.map(function (month, i) {
            return i ? temp[year][month] || 0 : +year;
        });
    });

result.unshift(columns);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

mhodges
mhodges

Reputation: 11116

You can actually get some pretty cool use out of ES6 features here (spread syntax and array destructuring)

The idea is to create an object containing your years/months/total tickets from your original data source, and then you can use that object to map the data into the structure you require, like so:

var data = [['tickets', 'month', 'year'], [1, "june", 2016], [3, "june", 2015], [1, "december", 2015]];

function mapTicketData(data) {
  var dataMap = data.slice(1).reduce(function(results, current, index) {
    var [tickets, month, year] = current;
    if (results.months.indexOf(month) === -1) {
      results.months.push(month);
    }
    if (results.years.indexOf(year) === -1) {
      results.years.push(year);
    }
    if (!results[year]) {
      results[year] = {};
    }
    if (!results[year][month]) {
      results[year][month] = 0;
    }
    results[year][month] += tickets;

    return results;
  }, { months: [], years: [] });

  return [['year', ...dataMap.months], ...dataMap.years.map(function(year) {
      return [year].concat(dataMap.months.map(function(month) {
        return dataMap[year][month] || 0;
      }));
    })
  ];
}

console.log(mapTicketData(data));

Upvotes: 0

Rafael Kennedy
Rafael Kennedy

Reputation: 1004

One possible approach to this: I'm grouping the dates into an object, creating a unique array of the months that have an entry, and then processing it into the array you want.

var inArray = [['tickets', 'month','year'], [1, "june",2016],[3, "june",2015],[1, "december",2015]]
var validMonths = {}

function dateReducer (acc, curr) {
  var year = curr[2]
  var month = curr[1]
  var num = curr[0]
  if (year === "year"){return acc}
  validMonths[month] = 0 // build unique array of valid months
  
  if (!acc[year]) {
    acc[year] = {}
    acc[year][month] = num
  } else {
    if (!acc[year][month]) {
      acc[year][month] = num
    } else {
      acc[year][month] += num
    }
  }
  return acc
}

var obj = inArray.reduce(dateReducer, {})
// This may be fine, depending on your needs
validMonths = Object.keys(validMonths)
var outArray = ["year"].concat(validMonths)

for (var year in obj) {
  if (obj.hasOwnProperty(year)){
    var subArray = [year]
    validMonths.forEach(v => {
      subArray.push(obj[year][v] || 0)
    })
    outArray.push(subArray)
  }
}

console.log(outArray)

Upvotes: 1

Related Questions