Home > Back-end >  Sort array of objects based first on a subarray and then on dates (without splitting the array)
Sort array of objects based first on a subarray and then on dates (without splitting the array)

Time:09-17

I have an array of objects that I want to sort based on whether or not they include a string.

I then want to sort those that do match the string by chronological order, and then the rest by chronological order.

So that

const role = waiter
const jobs = [
{ 
"date": "2021-09-30T00:00:00",
"role": [chef, porter]
},
{ 
"date": "2021-09-28T00:00:00",
"role": [waiter, chef]
},
{ 
"date": "2021-09-29T00:00:00",
"role": [waiter, chef]
},
{ 
"date": "2021-09-01T00:00:00",
"role": [chef]
},
]

Should become:

[
{ 
"date": "2021-09-28T00:00:00",
"role": [waiter, chef]
},
{ 
"date": "2021-09-29T00:00:00",
"role": [waiter, chef]
},
{ 
"date": "2021-09-01T00:00:00",
"role": [chef]
},
{ 
"date": "2021-09-30T00:00:00",
"role": [chef, porter]
},
]

So far the only solution I can find is to separate the array into two separate arrays. Sort them individually and then merge them back into one.

My current solution:

 const arrOne = jobs
    .filter((j) => j.role.includes(role))
    .sort((a, b) =>
      compareDesc(
        a.date,b.date
      )
    );

 const arrTwo = jobs
    .filter((j) => !j.role.includes(role))
    .sort((a, b) =>
      compareDesc(
        a.date,b.date
      )
    );

const finalArr = [...arrOne,...arrTwo]

Is there a more elegant solution?

Preferably one that doesn't require splitting the arrays into separate arrays?

CodePudding user response:

You can just use .sort and put in the sort conditions (if both match role, then by date, if first only, it goes first, it second only, it goes first, if none, then by date):

const chef = 'chef';
const porter = 'porter';
const waiter = 'waiter';

const role = waiter;

const jobs = [
{ 
"date": "2021-09-30T00:00:00",
"role": [chef, porter]
},
{ 
"date": "2021-09-28T00:00:00",
"role": [waiter, chef]
},
{ 
"date": "2021-09-29T00:00:00",
"role": [waiter, chef]
},
{ 
"date": "2021-09-01T00:00:00",
"role": [chef]
}
]


console.log(jobs.sort((a, b) => {
    if (a.role.includes(role) && b.role.includes(role)) {
        return new Date(a.date) - new Date(b.date);
    } else if (a.role.includes(role)) {
        return -1;
    } else if (b.role.includes(role)) {
        return 1;
    }
    return new Date(a.date) - new Date(b.date);
}));

CodePudding user response:

This should do it. first filter, then splice. the push found members to front

      const role = 'waiter'
      const jobs = [
      { 
      "date": "2021-09-30T00:00:00",
      "role": ['chef', 'porter']
      },
      { 
      "date": "2021-09-28T00:00:00",
      "role": ['waiter', 'chef']
      },
      { 
      "date": "2021-09-29T00:00:00",
      "role": ['waiter', 'chef']
      },
      { 
      "date": "2021-09-01T00:00:00",
      "role": ['chef']
      },
      ]


      const jobFound = jobs.some(job => job.role.includes(role)); // filter the roles that match.
      if (jobFound) {
        const sortedJobs = jobs.filter((job) => job.role.includes(role)); // filter desired data
        sortedJobs.sort((a, b) => a.date.localeCompare(b.date)); // sort by date
        sortedJobs.forEach((job) => jobs.splice(jobs.indexOf(job), 1)); // splice the object that were matched
        jobs.sort((a, b) => a.date.localeCompare(b.date)); // sort our original array
        jobs.unshift(...sortedJobs); // push ordered members to front of array
      }

      console.log(jobs);
  • Related