user2821694
user2821694

Reputation: 27

Creating a cumulative objects using javascript

I have one array of dates, and one array of objects. Each have a date property. I need to cumulatively sort the objects by date. So, for every date in the date array, I would like to create a cumulative object with every object who's date property is previous to the date in the date array.

For example, the following date array and object array:

['2017-11-5', '2018-3-1', '2018-3-22']

[{name: 'Jes', date: '2017-11-2'}, {name: 'Jill', date: '2018-1-5'}, {name: 'Joe', date: '2018-2-25'}, {name: 'Jack', date: '2018-3-21'}]

The desired output would be:

[{name: 'Jes', date: '2017-11-2'}]

[{name: 'Jes', date: '2017-11-2'}, {name: 'Jill', date: '2018-1-5'}, {name: 'Joe', date: '2018-2-25'}]

[{name: 'Jes', date: '2017-11-2'}, {name: 'Jill', date: '2018-1-5'}, {name: 'Joe', date: '2018-2-25'}, {name: 'Jack', date: '2018-3-21'}]

I am trying to do this with approximately 500 dates and 30,000 objects.

Here is a current code snippet, but I am having issues with performance, due to the number of objects I am iterating through.

    _.each(dtArray,function(i:Date){
  let dt = new Date(i);
  let filtered = _.filter(data,function(row){
    let dtVal = new Date(row['date']);
    return dtVal<=dt;
  });

Upvotes: 0

Views: 411

Answers (2)

Zakaria Chabihi
Zakaria Chabihi

Reputation: 56

There are several ways you can improve your algorithm while keeping the associative indices in enter image description here:

  • Precalculate date objects and only calculate them once for both people and dates
  • Sort dates in an ascending manner
  • Re-use precalculated/pre-filtered results, see Dynamic Programming
  • Save dates and people indices to keep the original order
  • Swap items between remaining and lastChunk to reduce remaining size if people[i].date < dates[j]

The algorithm code:

function filter(dates, people){
    let lastChunk = [];
    let remaining = people;
    let results = [];
    // precalculate dates, preserve indexes and sort by date
    let sortedDates = dates
        .map((value, index) => {
            return {
                date: new Date(value),
                index: index
            };
        })
        .sort((a, b) => {
            return a.date<b.date?-1:a.date==b.date?0:1;
        });
    let peopleWithDates = people.map((value, index) => {
        value.dateObject = new Date(value.date);
        value.index = index;
        return value;
    });
    for(const i in sortedDates){
        const comp = sortedDates[i].date
        remaining = remaining.filter((value, index) => {
            if(value.dateObject<=comp){
                let itemIndex = value.index;
                delete value.dateObject;
                delete value.index;
                lastChunk.splice(itemIndex, 0, value);
                return false;
            }else{
                return true;
            }
        });
        results[sortedDates[i].index] = [...lastChunk];
    }
    return results;
}

Upvotes: 0

Mark
Mark

Reputation: 92481

You can map() over the dates since you want one result array for each date. Then within the map you can filter() the people based on the date to create that array:

let dates = ['2017-11-5', '2018-3-1', '2018-3-22']

let people = [{name: 'Jes', date: '2017-11-2'}, {name: 'Jill', date: '2018-1-5'}, {name: 'Joe', date: '2018-2-25'}, {name: 'Jack', date: '2018-3-21'}]

let cumul = dates.map(d => people.filter(person => person.date <= d))
console.log(JSON.stringify(cumul, null, 2))

Upvotes: 2

Related Questions