Comparing two arrays and fill in missing values

Viewed 559

I want to compare the dates from 2 arrays and push the name from the matching date inside a new array. And then push '0' for missing dates.

This is what I've tried

var data = [{
  name: 'Amy',
  date: '2020-01-01'
}, {
  name: 'John',
  date: '2020-01-02'
}, {
  name: 'Sara',
  date: '2020-01-04'
}];

var fulldate = ['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'];
var newData = [];
var len = data.length;
for (var i = 0; i < len; i++) {
  if (data[i].date == fulldate[i]) {
    newData.push(data[i].name);
  } else if (data[i].date != fulldate[i]) {
    newData.push("0")
  }
}

console.log(newData);

The problem is that it stops after encountering the unmatched date:

Amy,John,0

This is what I need

Amy, John, 0, Sara, 0
6 Answers
  • On your code, you have used for-loop based on data variable length but the result has the same length with fulldate so it will be looped based on fulldate variable length.
  • Inside loop, you have compared fulldate[i] == data[i].date so compared only same index. Inside the loop, you need to use another loop to find the index of the matched date.

Instead of using for loop, you can simply do it using Array.prototype.map function. (Inside map function, using Array.prototype.findIndex, you can find the matched date index.)

var data = [{
  name: 'Amy',
  date: '2020-01-01'
}, {
  name: 'John',
  date: '2020-01-02'
}, {
  name: 'Sara',
  date: '2020-01-04'
}];

var fulldate = ['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'];

const result = fulldate.map((date) => {
  const existed = data.findIndex(item => item.date === date);
  return existed >= 0 ? data[existed].name : 0
});
console.log(result);

var data = [{
  name: 'Amy',
  date: '2020-01-01'
}, {
  name: 'John',
  date: '2020-01-02'
}, {
  name: 'Sara',
  date: '2020-01-04'
}];
var fulldate = [
  '2020-01-01',
  '2020-01-02',
  '2020-01-03',
  '2020-01-04',
  '2020-01-05'
];
var newData = [];
for(var i = 0; i < fulldate.length; i++) {
  var found = false;
  for(var k in data) {
    if(data[k].date == fulldate[i]) {
      newData.push(data[k].name);
      found = true;
      break;
    }
  }
  if(!found)
    newData.push("0");
}
console.log(newData);

The best approach is always to use map and filter. Use map function on the fulldate The obj filters out the object (if present) with same date, as of current el value. I have used ternary operator in the return statement which returns name if object is present, and 0 otherwise.

var data = [{
  name: 'Amy',
  date: '2020-01-01'
}, {
  name: 'John',
  date: '2020-01-02'
}, {
  name: 'Sara',
  date: '2020-01-04'
}];

var fulldate = ['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'];


var result = fulldate.map((el) => {
  let obj = data.filter(item => (item.date == el))  
  return (obj[0]) ? obj[0].name : 0;
})

console.log(result);

Suppose the arrays are ordered by date already, use a variable dataIdx to iterate data and Array.map() to simplify the for loop.

var data = [{name:'Amy', date:'2020-01-01'}, {name:'John', date:'2020-01-02'}, {name:'Sara', date:'2020-01-04'}];

var fulldate = ['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'];

var dataIdx = 0;
var newData = fulldate.map(date => data[dataIdx] && data[dataIdx].date == date ? data[dataIdx++].name : '0');
console.log(newData);

for variable declaration, use 'let' or 'const' instead of var. reason: var vs let vs const

And, the result you are looking for can be done using map & find js func.

const fulldate = ["2020-01-01", "2020-01-02", "2020-01-03", "2020-01-04", "2020-01-05"];
const data = [
 {name: "Amy", date: "2020-01-01"},
 {name: "John", date: "2020-01-02"},
 {name: "Sara", date: "2020-01-04"}
];

const result = fulldate.map(date => {
    const matchingDate = data.find(nameDateObj => nameDateObj['date'] === date);
    return matchingDate ? matchingDate['name'] : 0;
});

console.log(result)

fyi: this can also be done using findIndex instead of find too.

fulldate.map(date => {
     const matchingDateIndex = data.findIndex(nameDateObj => nameDateObj['date'] === date);
     return matchingDateIndex > -1 ? data[matchingDateIndex]['name'] : 0; 
});

For shortest solution you should combine map and find. Here is a oneliner:

const data = [{
  name: 'Amy',
  date: '2020-01-01'
}, {
  name: 'John',
  date: '2020-01-02'
}, {
  name: 'Sara',
  date: '2020-01-04'
}];

const fulldate = ['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'];

const result = fulldate.map(x => (data.find(y => y.date === x) || {name: 0}).name)

console.log(result)

Related