We have an array with data and I want to sort it by users
key:
If users
have 1 object, I sort by its name
property.
If users
have more than 1 entry, I sort by users.length
.
Example:
DESCENDING: Zorya, Gorya, Dorya, Borya, Aorya, 4, 2, 0
ASCENDING: Aorya, Borya, Dorya, Gorya, Zorya, 2, 4, 0
This is what I've done so far:
const array = [{
name: "qw",
users: [
{ name: "Borya" },
],
}, {
name: "qw",
users: [
{ name: "Gorya" },
],
}, {
name: "qw",
users: [
{ name: "Zorya" },
]
}, {
name: "qw",
users: [
{ name: "Var" },
{ name: "Var2" },
],
}, {
name: "qw",
users: [],
}, {
name: "qw",
users: [
{ name: "Aorya" },
],
}, {
name: "qw",
users: [
{ name: "rwerwerwe" },
{ name: "tregdf" },
{ name: "gdfgdf" },
{ name: "Vayetrtertrr2" },
]
}, {
name: "qw",
users: [
{ name: "Dorya" },
],
}];
function orderCustomBy(collection, key, direction) {
const direct = direction === "desc" ? -1 : 1;
let compare = (a, b) => {
if (a === null) return -1;
if (b === null) return 1;
// Just commenting this out because there's no `intlCollator` in here:
// return intlCollator.compare(a, b);
};
if (key === "users") {
compare = (a, b) => {
// What should go in here?
// intlCollator.compare(a[0].name, b[0].name);
return 1;
};
}
return [].concat(collection).sort((a, b) => {
const result = compare(a[key], b[key]);
return result * direct;
});
}
console.log(orderCustomBy(array, 'users', 'asc')
.map(item => item.users.length === 1 ? item.users[0].name : item.users.length));
console.log(orderCustomBy(array, 'users', 'desc')
.map(item => item.users.length === 1 ? item.users[0].name : item.users.length));
.as-console-wrapper {
max-height: 100% !important;
}
You basically need to account for a few different combinations inside the compare
function when key === 'users
:
Both have a single user, so we compare user[0].name
.
Only a
has a single user, so a
goes before b
.
Only b
has a single user, so b
goes before a
.
None have a single user, so we just compare users.length
.
It will look something like this:
if (a.users.length === 1 && b.users.length === 1) {
// If both have a single user, sort by users[0].name:
return a.users[0].name.localeCompare(b.users[0].name);
} else if (a.users.length === 1) {
// If only `a` has a single user, `a` goes before `b`:
return -1;
} else if (b.users.length === 1) {
// If only `b` has a single user, `b` goes before `a`:
return 1;
}
// Otherwise, sort by users.length:
return a.users.length - b.users.length;
Here you can see it in action:
const array = [{
name: "qw",
users: [
{ name: "Borya" },
],
}, {
name: "qw",
users: [
{ name: "Gorya" },
],
}, {
name: "qw",
users: [
{ name: "Zorya" },
]
}, {
name: "qw",
users: [
{ name: "Var" },
{ name: "Var2" },
],
}, {
name: "qw",
users: [],
}, {
name: "qw",
users: [
{ name: "Aorya" },
],
}, {
name: "qw",
users: [
{ name: "rwerwerwe" },
{ name: "tregdf" },
{ name: "gdfgdf" },
{ name: "Vayetrtertrr2" },
]
}, {
name: "qw",
users: [
{ name: "Dorya" },
],
}];
function orderCustomBy(collection, key, direction) {
const direct = direction === "desc" ? -1 : 1;
let compare;
if (key === "users") {
compare = (a, b) => {
if (a.users.length === 1 && b.users.length === 1) {
// If both have a single user, sort by users[0].name:
return a.users[0].name.localeCompare(b.users[0].name);
} else if (a.users.length === 1) {
// If only `a` has a single user, `a` goes before `b`:
return -1;
} else if (b.users.length === 1) {
// If only `b` has a single user, `b` goes before `a`:
return 1;
}
// Otherwise, sort by users.length:
return a.users.length - b.users.length;
};
} else {
compare = (a, b) => {
if (a === null) return -1;
if (b === null) return 1;
// Just commenting this out because there's no `intlCollator` in here:
// return intlCollator.compare(a, b);
};
}
return [].concat(collection).sort((a, b) => compare(a, b) * direct);
}
console.log(orderCustomBy(array, 'users', 'asc')
.map(item => item.users.length === 1 ? item.users[0].name : item.users.length));
console.log(orderCustomBy(array, 'users', 'desc')
.map(item => item.users.length === 1 ? item.users[0].name : item.users.length));
.as-console-wrapper {
max-height: 100% !important;
}