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