admin管理员组

文章数量:1323738

I have a json file with multiple transactions with a date and a price attribute. Now I want to pare the dates and if they are in the same month and year I want to sum up the prices.

JSON:

transactions: [
{
  date: "2017-11-17",
  price: "28",
},
{
  ...
}

JavaScript:

request.onload = function() {
  for(const transaction of request.response.transactions) {
    let year = new Date(transaction.date).getFullYear();
    let month = new Date(transaction.date).getMonth();

    console.log(year + ' ' + month);  // output: 2017-11 ...
  }
};

I tried to loop over the json object but I struggle to find a solution to pare the dates.

I have a json file with multiple transactions with a date and a price attribute. Now I want to pare the dates and if they are in the same month and year I want to sum up the prices.

JSON:

transactions: [
{
  date: "2017-11-17",
  price: "28",
},
{
  ...
}

JavaScript:

request.onload = function() {
  for(const transaction of request.response.transactions) {
    let year = new Date(transaction.date).getFullYear();
    let month = new Date(transaction.date).getMonth();

    console.log(year + ' ' + month);  // output: 2017-11 ...
  }
};

I tried to loop over the json object but I struggle to find a solution to pare the dates.

Share Improve this question asked Dec 8, 2017 at 13:39 DarioDario 6401 gold badge12 silver badges29 bronze badges 5
  • What is the expected output ? – ChrisR Commented Dec 8, 2017 at 13:44
  • What's your expected output? An object array containing the sum for each month? (ex - [{month: 2017-10, priceTotal: 123}, month: 2017-11, priceTotal: 234}] – nipuna-g Commented Dec 8, 2017 at 13:44
  • The expected output is an array of prices sorted for each month and year. – Dario Commented Dec 8, 2017 at 13:45
  • @nipuna777 yeah, that would be perfect =). But you can also help by just explaining how I can effectively pare my dates for each month and year. Thanks for your help – Dario Commented Dec 8, 2017 at 13:47
  • Do not use the built-in parser: new Date(transaction.date).getFullYear() is problematic as your string format will be treated as UTC by conforming browsers. So depending on your timezone, some dates for the first or last day of the month will appear to be in the adjacent month. Also see Why does Date.parse give incorrect results? – RobG Commented Dec 8, 2017 at 21:27
Add a ment  | 

5 Answers 5

Reset to default 4

Edit: Edited example with Object.assign instead of Object spread.

You'll need to use reduce to sum the prices. See ments for details.

const transactions = [{
    date: "2017-11-17",
    price: "28",
  },
  {
    date: "2017-12-17",
    price: "23",
  },
  {
    date: "2017-11-17",
    price: "12",
  },
  {
    date: "2017-10-17",
    price: "55",
  },
  {
    date: "2017-11-17",
    price: "09",
  },
];

const sumTransactions = (transactions) => {

  const summed = transactions.reduce((acc, current) => {
    // Get the current date object
    const date = new Date(current.date);
    // Create your key/identifier
    const key = `${date.getFullYear()}-${date.getMonth() + 1}`;
    // Retreive the previous price from the accumulator
    const previousPrice = acc[key]; // Might also return undefined
    // Create your temp current price value, and be sure to deal with numbers.
    let currentPrice = Number(current.price);
    // If you had a previous value (and not undefined)
    if (previousPrice) {
      // Add it to our value
      currentPrice += Number(previousPrice);
    }
    // Return the future accumulator value
    return Object.assign(acc, {
      [key]: currentPrice, // new values will overwrite same old values
    })
  }, {})

  // Once we have all values, get the dates, and sort them (default: earlier first)
  // Return an array of each value from the summed object to our sortedArray
  const sortedArray = Object.keys(summed).sort().map((val) => {
    return summed[val];
  });

  console.log("sortedArray", sortedArray);
};

sumTransactions(transactions);

I experimented a bit and came up with this solution:

var transactions = [
    {
        date: "2017-11-17",
        price: "28",
    },
    {
        date: "2017-12-17",
        price: "22",
    },
    {
        date: "2017-12-17",
        price: "20",
    }
]

var sumedUpDates = [];
var prices = [];

function isDateSumedUp(date) {
    return sumedUpDates.indexOf(date.substring(0, 7)) !== -1;
}

function sumUpDate(date) {
    var sum = 0;

    transactions.forEach(t => {
        if(t.date.substring(0, 7) === date.substring(0, 7)) {
            sum += parseInt(t.price);
        }
    });

    sumedUpDates.push(date.substring(0, 7));
    prices.push(sum);
}

transactions.forEach(t => {
    if(!isDateSumedUp(t.date)) {
        sumUpDate(t.date);
    }
});

var obj = {};

sumedUpDates.forEach((d, i) => obj[d] = prices[i]);

console.log(obj);

This solutions uses map to format your dates into year/month format for each object entry and then reduce to sum them by those separated dates.

const transactions = [
  {date:"2017-11-17", price: "28",}, 
  {date:"2017-12-17", price: "28",}, 
  {date:"2017-11-17", price: "20",},
  {date:"2017-12-17", price: "2",}, 
  {date:"2017-11-17", price: "58",}, 
  {date:"2017-11-17", price: "8",}, 
  {date:"2017-10-17", price: "30",}, 
  {date:"2018-11-17", price: "1",},
];

const mapper = single => {
  let d = single.date.split('-');
  let p = Number(single.price);
  return { year: d[0], month: d[1], price: p };
}

const reducer = (group, current) => {
  let i = group.findIndex(single => (single.year == current.year && single.month == current.month));
  if (i == -1) {
    return [ ...group, current ];
  }

  group[i].price += current.price;
  return group;
};

const sumPrices = transactions.map(mapper).reduce(reducer, []);
console.log(sumPrices);
  
  

var array = [];
for (var i = 0; i < transactions.length; i++) {
    var date = new Date(transactions[i].date);
    var ym = date.getFullYear() + "-" + date.getMonth();
    if (array[ym] == null) {
        array[ym] = 0;
    }
    array[ym] += parseInt(transactions[i].price);
}

With this data

var transactions = [{
                date: "2017-11-17",
                price: "28",
            },
            {
                date: "2017-12-17",
                price: "5",
            },
            {
                date: "2016-02-17",
                price: "28",
            },
            {
                date: "2015-11-17",
                price: "25",
            },
            {
                date: "2016-02-17",
                price: "12",
            },
            {
                date: "2017-11-17",
                price: "50",
            }
        ];

This will give you the sum of all of the year-months duplicates like this :

[
    2017-10: 78, 
    2017-11: 5, 
    2016-1: 40, 
    2015-10: 25
]

Another solution is reduce:

var transactions = [
  {date: "2017-11-17",price: "28"},
  {date: "2017-12-17",price: "22"},
  {date: "2017-12-17",price: "20"}
];

var result = transactions.reduce(function(acc, obj) {
  var key = obj.date.substr(0,7);
  acc[key] = (acc[key] || 0) + +obj.price;
  return acc;
}, Object.create(null));

console.log(result);

本文标签: JavaScript Compare dates in an array and sum the quotpricequot for each monthyearStack Overflow