Greg Ostry
Greg Ostry

Reputation: 1231

How to fill in missing months in an array using javascript

Is there a way how can i complete missing month and sale in an incomplete array.

sometimes i get a query like this:

var sales = [

    {'month': '04', 'sale': 126},
    {'month': '06', 'sale': 165},
    {'month': '07', 'sale': 10},
    {'month': '08', 'sale': 20},
    {'month': '09', 'sale': 211},
    {'month': '10', 'sale': 27},
    {'month': '11', 'sale': 112},
];

and i need to add the missing months with sale: 0.

I thought i can make a second array with all months and then compare this two arrays and pick the duplicates to the array with all months:

var compareArray = [

    {'month': '01', 'sale': 0},
    {'month': '02', 'sale': 0},
    {'month': '03', 'sale': 0},
    {'month': '04', 'sale': 0},
    {'month': '05', 'sale': 0},
    {'month': '06', 'sale': 0},
    {'month': '07', 'sale': 0},
    {'month': '08', 'sale': 0},
    {'month': '09', 'sale': 0},
    {'month': '10', 'sale': 0},
    {'month': '11', 'sale': 0},
    {'month': '12', 'sale': 0},
];

Upvotes: 6

Views: 2106

Answers (5)

trincot
trincot

Reputation: 350034

Instead of pre-defining the 12-entries array, you could use Array(12).keys() and use Array.from to map that to the desired output:

var sales = [{'month': '04', 'sale': 126}, {'month': '06', 'sale': 165}, {'month': '07', 'sale': 10},  {'month': '08', 'sale': 20}, {'month': '09', 'sale': 211}, {'month': '10', 'sale': 27}, {'month': '11', 'sale': 112}];

sales = Array.from(Array(12).keys(), month => 
    sales.find(sale => +sale.month === month+1) || { month: ("0"+(month+1)).substr(-2), sale: 0 }
);

console.log(sales);

Edit in 2025: With the addition of iterator helper methods in ECMAScript 2025, this can be rewritten as a chain:

let sales = [{'month': '04', 'sale': 126}, {'month': '06', 'sale': 165}, {'month': '07', 'sale': 10},  {'month': '08', 'sale': 20}, {'month': '09', 'sale': 211}, {'month': '10', 'sale': 27}, {'month': '11', 'sale': 112}];

sales = Array(12).keys().map(month => 
    sales.find(sale => +sale.month === ++month) ?? { month: ("0"+month).substr(-2), sale: 0 }
).toArray();

console.log(sales);

Upvotes: 9

Tom O.
Tom O.

Reputation: 5941

You can use the same approach I used below. Bascially just loop 1 - 12 and if you find missing months, add them to the array. Once you have all your months in the array, simply sort in ascending order based on month number.

const sales = [{
    'month': '04',
    'sale': 126
  },
  {
    'month': '06',
    'sale': 165
  },
  {
    'month': '07',
    'sale': 10
  },
  {
    'month': '08',
    'sale': 20
  },
  {
    'month': '09',
    'sale': 211
  },
  {
    'month': '10',
    'sale': 27
  },
  {
    'month': '11',
    'sale': 112
  }
];

function generateSalesReport(salesData) {
  const monthsWithSales = [];
  const salesReport = [];
  salesData.forEach(el => {
    monthsWithSales.push(Number.parseInt(el.month));
    salesReport.push(el);
  });

  //Fill in the missing months
  for (let i = 1; i <= 12; i++) {
    if (monthsWithSales.indexOf(i) === -1) {
      let monthStr = i.toString();
      salesReport.push({
        'month': monthStr.length < 2 ? '0' + monthStr : monthStr,
        'sale': 0
      });
    }
  }

  //Sort the sales report array
  return salesReport.sort((a, b) => parseInt(a.month) - parseInt(b.month));
}

console.log(generateSalesReport(sales));

Upvotes: 0

dhilt
dhilt

Reputation: 20744

An approach based on .map and .find array methods

const data = [
    {'month': '04', 'sale': 126},
    {'month': '06', 'sale': 165},
    {'month': '07', 'sale': 10},
    {'month': '08', 'sale': 20},
    {'month': '09', 'sale': 211},
    {'month': '10', 'sale': 27},
    {'month': '11', 'sale': 112},
];

const result = [...Array(12)].map((m, i) => {
  const month = i < 9 ? '0' + (i + 1) : String(i + 1);
  return data.find(d => d.month === month) || { month, sale: 0 };
});

Upvotes: 3

Pointy
Pointy

Reputation: 413702

Because your month numbers are numbers, and span a convenient range, you can use them as array indexes:

var yearSales = sales.reduce(function(rv, month) {
  a[parseInt(month.month, 10)] = month;
  return a;
}, []);

Then you can find the empty slots:

for (let i = 0; i < 12; i++)
  if (!yearSales[i])
    yearSales[i] = { month: i, sales: 0 };

(I didn't use .forEach() because it skips empty slots, and those are the ones I want to target.)

Upvotes: 0

Ankit Agarwal
Ankit Agarwal

Reputation: 30739

You can use a simple for loop then Array.sort() to get the desired output:

var sales = [{
    'month': '04',
    'sale': 126
  },
  {
    'month': '06',
    'sale': 165
  },
  {
    'month': '07',
    'sale': 10
  },
  {
    'month': '08',
    'sale': 20
  },
  {
    'month': '09',
    'sale': 211
  },
  {
    'month': '10',
    'sale': 27
  },
  {
    'month': '11',
    'sale': 112
  },
];
for (var i = 1; i <= 12; i++) {
  var existObj = sales.find(item => +item.month === i);
  if (!existObj) {
    sales.push({
      'month': i > 9 ? i : '0' + i,
      'sale': 0
    });
  }
}
sales.sort(function(a, b) {
  return +a.month - +b.month;
});
console.log(sales);

Upvotes: 0

Related Questions