Below is my sort function but I want to display the ones with a code to be at the top. I want to sort my array of objects by code, then by description. Right now, the items without a code is being placed at the top of the order.
data = [
{
code: "1.1",
description: "aaa"
},
{
code: "",
description: "bbb"
},
{
code: "1.2",
description: "ccc"
}
]
let sortedData = data.sort(function(a, b) {
let codeA = a.code
let codeB = b.code
let descriptionA = a.description.toLowerCase()
let descriptionB = b.description.toLowerCase()
if (codeA < codeB) return -1
if (codeA > codeB) return 1
if (descriptionA < descriptionB) return -1
if (descriptionA > descriptionB) return 1
return 0
})
return sortedData
Current order:
["bbb", "aaa", "ccc"]
Expected order:
["aaa", "ccc", "bbb"]
Below is my sort function but I want to display the ones with a code to be at the top. I want to sort my array of objects by code, then by description. Right now, the items without a code is being placed at the top of the order.
data = [
{
code: "1.1",
description: "aaa"
},
{
code: "",
description: "bbb"
},
{
code: "1.2",
description: "ccc"
}
]
let sortedData = data.sort(function(a, b) {
let codeA = a.code
let codeB = b.code
let descriptionA = a.description.toLowerCase()
let descriptionB = b.description.toLowerCase()
if (codeA < codeB) return -1
if (codeA > codeB) return 1
if (descriptionA < descriptionB) return -1
if (descriptionA > descriptionB) return 1
return 0
})
return sortedData
Current order:
["bbb", "aaa", "ccc"]
Expected order:
["aaa", "ccc", "bbb"]
4 Answers
Reset to default 4- Using the xor
^
operator, we can check to see if one of the codes is falsy while the other is truthy. In this case, falsy being blank. If this is true, the one with a blank should be greater than the other so it sorts after it. - Otherwise, subtract the codes, then the descriptions for normal sorting.
var data = [
{
code: "1.1",
description: "aaa"
},
{
code: "",
description: "bbb"
},
{
code: "1.2",
description: "ccc"
}
];
let sortedData = data.sort(function(a, b) {
let codeA = a.code;
let codeB = b.code;
let descriptionA = a.description.toLowerCase();
let descriptionB = b.description.toLowerCase();
if (codeA ^ codeB) {
return !codeA ? 1 : -1;
}
return codeA.localeCompare(codeB) || descriptionA.localeCompare(descriptionB);
});
console.log(sortedData)
One way to make ""
appear at the end is just to prefix the pare values, so if the code is "", the value bees "B"
, if it's 1.1
it bee A1.1
, so A1.1
< B
..
Doing this is also very easy to modify to do all sort of fancy sorting, eg. Lets say you wanted to sort alphabetically, but wanted all K's
at the start, and all B's
at the end, strange thing to do. But very easy to make happen. I suppose you could call it sorting with exceptions.
Here is a working example.
const data = [
{
code: "1.1",
description: "aaa"
},
{
code: "",
description: "bbb"
},
{
code: "1.2",
description: "ccc"
}
];
data.sort((
{ code: code1, description: desc1 },
{ code: code2, description: desc2 }
) => {
code1 = (code1 === "" ? "B" : "A") + code1;
code2 = (code2 === "" ? "B" : "A") + code2;
return code1.localeCompare(code2) ||
desc1.localeCompare(desc2);
});
console.log(data);
Your test case is a little lax and makes it hard to spot some bugs. You are usually better off using localeCompare
to pare strings. You can make a case for two very plain, but readable if
statements followed by a localeCompare
of the strings:
Here's a few extra test cases
let data = [{
code: "1.1",
description: "ddd"
},
{
code: "1.101",
description: "ccc"
},
{
code: "",
description: "eee"
},
{
code: "1.2",
description: "De"
},
{
code: "1.1",
description: "aaa"
},
{
code: "",
description: "bbb"
},
{
code: "1.2",
description: "ccc"
},
{
code: "1.2",
description: "AbcD"
}
]
data.sort((a, b) => {
if (a.code && !b.code) return -1
if (b.code && !a.code) return 1
return a.code.localeCompare(b.code) || a.description.localeCompare(b.description)
})
console.log(data)
:
Since your second code is empty you will pare an empty string and Javascript will cast your Float
to a String
. Oddly if you pare any string if it is smaller than any other string it will always return true
! The opposite is also true - if you pare it to be bigger than any other string it will always return false
.
"" < "1.1" // return true
"1.1" < "" // return true!
"" > "1.1" // return false
"1.1" > "" // return false!
To solve your problem you could add two additional checks before your other checks
if (codeA === "" && codeA.length < codeB.length) return 1;
if (codeB === "" && codeA.length > codeB.length) return -1;
If codeA or codeB is a String
you can simply pare the length of the strings.