6

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},
];
1
  • Make an array such that the month number is the index into that array, and then fill in the empty slots with new 0-sale objects. Commented Aug 9, 2018 at 13:41

5 Answers 5

9

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);

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

7 Comments

I was surprised to see the .from - My ES6 is shaky when it comes to arrows
[...Array(12)].map also saves the from
It saves the from, but it creates an extra array before the map happens. The Array.from callback mechanism avoids the creation of that intermediate array.
There would be nothing to map then, @mplungjan: there are no entries in Array(12), just a length.
[...Array(12)] could be mapped
|
3

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 };
});

Comments

0

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);

Comments

0

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.)

Comments

0

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));

Comments

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.