Let's say we have an array of objects with mixed name
values (nums, cyrillic, english):
(If the code doesn't work for you, change undefined
to 'ru'
, it will also change the sorting structure)
let ascending = true
var items = [
{name: 'c', value: ''},
{name: 'b', value: ''},
{name: 'a', value: ''},
{name: 'д', value: ''},
{name: 'в', value: ''},
{name: '41', value: ''},
{name: 'а', value: ''},
{name: 'б', value: ''},
{name: '0', value: ''},
{name: '31', value: ''},
{name: '4', value: ''},
{name: 'г', value: ''}
]
items.sort(function (a, b) {
// ascending order
if (ascending) {
return a.name.localeCompare(b.name, undefined, { numeric: true });
}
// descending order
else {
return b.name.localeCompare(a.name, undefined, { numeric: true });
}
})
console.log(items);
I get the sorted array in ascending order with the following structure:
Result when ascending = true
:
{name: "0", value: ""}
{name: "31", value: ""}
{name: "4", value: ""}
{name: "41", value: ""}
{name: "a", value: ""}
{name: "b", value: ""}
{name: "c", value: ""}
{name: "а", value: ""}
{name: "б", value: ""}
{name: "в", value: ""}
{name: "г", value: ""}
{name: "д", value: ""}
I need it to be able to sort the array in descending order when ascending = false
and retain the structure:
Needed result when ascending = false
:
{name: "41", value: ""}
{name: "31", value: ""}
{name: "4", value: ""}
{name: "0", value: ""}
{name: "c", value: ""}
{name: "b", value: ""}
{name: "a", value: ""}
{name: "д", value: ""}
{name: "г", value: ""}
{name: "в", value: ""}
{name: "б", value: ""}
{name: "а", value: ""}
When I change ascending = false
and change positions of b.name
with a.name
it just flips the whole array upside down instead of flipping the values in their "category" (nums, english, cyrillic).
I'm not sure how to do it properly. I mean, reversing the array reverses the values, so should I just restructure the array "categories" after it flipped the array? Something like this maybe:
get all the objects with numbers with isNaN()
and move them on top
then get items containing only a-z
at [0]
and move them below the numbers "category"
everything else just stays on the bottom
If you are have a mechanism to identify numbers, english and non-english strings you can use the following idea:
var items = [
{ name: "c", value: "" },
{ name: "b", value: "" },
{ name: "a", value: "" },
{ name: "д", value: "" },
{ name: "в", value: "" },
{ name: "41", value: "" },
{ name: "а", value: "" },
{ name: "б", value: "" },
{ name: "0", value: "" },
{ name: "31", value: "" },
{ name: "4", value: "" },
{ name: "г", value: "" }
];
function sortFunctionMaker(ascending) {
function isNumber(str) {
return Number.isNaN(Number(str)) === false;
}
function isEnglish(str) {
return /^[a-zA-Z]+$/.test(str);
}
return function(a, b) {
var aw, bw;
if (isNumber(a.name)) {
aw = 1;
} else if (isEnglish(a.name)) {
aw = 2;
} else {
aw = 3;
}
if (isNumber(b.name)) {
bw = 1;
} else if (isEnglish(b.name)) {
bw = 2;
} else {
bw = 3;
}
if (aw !== bw) {
// a and b belong to different categories
// no further comparison is needed
return aw - bw;
} else if (aw === 1) {
// both are numbers
// sort mathematically
return (ascending ? 1 : -1) * (a.name - b.name);
} else {
// both are english or otherwise
// sort using localeCompare
return (ascending ? 1 : -1) * a.name.localeCompare(b.name);
}
}
}
items.sort(sortFunctionMaker(true));
console.log("Ascending");
items.forEach(function(item) {
console.log(item.name);
});
items.sort(sortFunctionMaker(false));
console.log("Descending");
items.forEach(function(item) {
console.log(item.name);
});
console.groupEnd();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With