2

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 4

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)

Sign up to request clarification or add additional context in comments.

2 Comments

What does 'aaa' - 'bbb' equal? This does not sort the description strings correctly in cases where the code is equal. It looks like it works because they are already sorted.
@MarkMeyer fixed it to use the localeCompare properly.
1

One way to make "" appear at the end is just to prefix the compare values, so if the code is "", the value becomes "B", if it's 1.1 it become 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);

Comments

1

Your test case is a little lax and makes it hard to spot some bugs. You are usually better off using localeCompare to compare 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)

:

Comments

0

Since your second code is empty you will compare an empty string and Javascript will cast your Float to a String. Oddly if you compare any string if it is smaller than any other string it will always return true! The opposite is also true - if you compare 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 compare the length of the strings.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.