Home > Mobile >  How to merge two arrays of dates and keep the order for other array
How to merge two arrays of dates and keep the order for other array

Time:09-30

I have this code:

var dates1 = ['1/2021', '1/2021', '12/2020'];
var values1 = ['-2500', '-150', '-10000'];

var dates2 = ['2/2021', '3/2021', '1/2021'];
var values2 = ['3000', '1000', '3000'];

What I need is to merge the dates1 with dates2, and keep the same order for values1 and values2 adding a 0 for the dates that has none values, so the result would be this:

var dates = ['12/2020', '1/2021', '2/2021', '3/2021'];
var values1 = ['-10000', '-2650', '0', '0'];
var values2 = ['0', '3000', '3000', '1000'];

To merge the arrays of dates I'm using this code:

var dates = dates1.concat(dates2);

I just don't know how can I keep the same order for values1 and values2 adding a 0 for none values. Any suggestion ? Thank you !

CodePudding user response:

Break down the algorithm into the smallest steps, then order the steps after each other:

const dates1 = ['1/2021', '1/2021', '12/2020'];
const values1 = ['-2500', '-150', '-10000'];

const dates2 = ['2/2021', '3/2021', '1/2021'];
const values2 = ['3000', '1000', '3000'];

// summing the arrays & keeping track of how
// the values should be ordered
const reduceArr = ({ dates, values }) => {
  const reduced = dates.reduce((a, c, i) => {
    if (typeof a[c] === 'undefined') a[c] = 0
    a[c]  = Number(values[i])
    return a
  }, {})
  const filteredDates = [...new Set([...dates])]
  const filteredValues = filteredDates.map(date => reduced[date])
  return {
    filteredDates,
    filteredValues,
  }
}

// merging the different dates arrays
const mergeDates = ({ dates1, dates2 }) => {
  return [...new Set([...dates1, ...dates2])]
}

// time-sorting the merged arrays
const sortDates = ({ dates }) => {
  return [...dates].sort((a, b) => {
    const [m1, y1] = a.split('/')
    const [m2, y2] = b.split('/')
    return new Date(y1, m1, 1) - new Date(y2, m2, 1)
  })
}

// mapping values based on the orders &
// adding 0 if no value is found
const mapToDates = ({ sortedDates, reducedArr }) => {
  return sortedDates.map(date => {
    const idx = reducedArr.filteredDates.indexOf(date)
    return idx === -1 ? 0 : reducedArr.filteredValues[idx]
  })
}

// actually executing the steps:
const mergedDates = mergeDates({ dates1, dates2 })
const sortedDates = sortDates({ dates: mergedDates })

const reducedArr1 = reduceArr({ dates: dates1, values: values1 })
const mapValues1 = mapToDates({ sortedDates, reducedArr: reducedArr1 })

const reducedArr2 = reduceArr({ dates: dates2, values: values2 })
const mapValues2 = mapToDates({ sortedDates, reducedArr: reducedArr2 })

console.log('mapValues1', mapValues1)
console.log('mapValues2', mapValues2)

CodePudding user response:

I think that what you need is that:

Array.prototype.unique = function() {
    var a = this.concat();
    for(var i=0; i<a.length;   i) {
        for(var j=i 1; j<a.length;   j) {
            if(a[i] === a[j])
                a.splice(j--, 1);
        }
    }
    return a;
};

stringToDate = function(str) {
    return str.substring(str.search("/") 1, str.search("/") 5)   "-"   (Number(str.substring(0, str.search("/"))) < 10 ? '0' : '')   str.substring(0, str.search("/") )   "-15T00:00:00Z";
}

dateToString = function(dt) {
    dt = new Date(dt);
  return (1   dt.getMonth())   "/"   dt.getFullYear() ;
}

var dates1 = [stringToDate('1/2021'), stringToDate('1/2021'), stringToDate('12/2020')];
var values1 = ['-2500', '-150', '-10000'];
var dates2 = [stringToDate('2/2021'), stringToDate('3/2021'), stringToDate('1/2021')];
var values2 = ['3000', '1000', '3000'];

var dates_out = dates1.concat(dates2).unique().sort();
var values1_out = new Array(dates_out.length);
var values2_out = new Array(dates_out.length);

dates_out.forEach((dt, i) => {
    dates_out[i] = dateToString(dates_out[i]);
    values1_out[i] = 0;
  values2_out[i] = 0;
    dates1.forEach((dt1, i1) => {
    if (dt1 === dt) {
        if (values1_out[i] != undefined)
            values1_out[i] = values1_out[i]   Number(values1[i1]);
      else 
        values1_out[i] = Number(values1[i1]);
    }  
  });
  dates2.forEach((dt2, i2) => {
    if (dt2 === dt) {
        if (values2_out[i] != undefined)
            values2_out[i] = values2_out[i]   Number(values2[i2]);
      else 
        values2_out[i] = Number(values2[i2]);
    }  
  });
});
console.log(dates_out);
console.log(values1_out);
console.log(values2_out);

I don't know if this is the best solution. I would create dictionaries to work with the data. I understood that you need to order the dates (the first result being 12/2020 instead of 1/2021). I also understood that you need the dates as a string, but if you need the date as a datatype, you can remove the part where I convert it back to a string.

  • Related