-2

I am having difficulty figuring out a solution.

I have an array similar to this.

// Original array 
const orig_array = ["2", "10", "01A", "1A", "02B", "1","03B"]; 

// The sorted array needs to be like this. 
sorted_array = ["1", "1A", "01A", "2", "02B", "03B", "10"]; 

I have tried writing a custom sort function like this but I am unable to find a solution. I appreciate any help.

 const orig_array = ["2", "10", "01A", "1A", "02B", "1","03B"];

 const sorted_array = orig_array.sort((a, b) => {
  if (a - b) {
   return a - b;
  }
 if (a.localeCompare(b) === -1) {
  return a.length - b.length;
 } else {
 return 1;
}
});
console.log(sorted_array);
MSH
  • 297
  • 1
  • 3
  • 12
  • 3
    What is your criteria for sorting? – Unmitigated Nov 03 '21 at 02:05
  • 1
    You should probably clarify that you're looking for a natural and not lexicographic sort – Dario Petrillo Nov 03 '21 at 02:06
  • Why is `10 > 1A`? That's unusual. – jabaa Nov 03 '21 at 02:09
  • 2
    @jabaa It's a natural sort, and `10 > 1` – Barmar Nov 03 '21 at 02:09
  • 1
    @Unmitigated Why do you think this is not a duplicate of the [canonical "natural sort" question](https://stackoverflow.com/questions/15478954/sort-array-elements-string-with-numbers-natural-sort)? The accepted answer there does produce the exact result the OP wants. For anything else, this question should be closed as unclear. – Bergi Nov 03 '21 at 02:18
  • @Bergi The accepted answer may place `01A` before `1A`. – Unmitigated Nov 03 '21 at 02:20
  • @Unmitigated Ah, right, they are considered equal by a normal natural sort. Change `return ax.length - bx.length;` to `return ax.length - bx.length || a.length - b.length;` for placing the one with leading zeroes after. – Bergi Nov 03 '21 at 02:24

1 Answers1

4

You can first apply parseInt to both strings to get the first numeric parts and subtract them. If the numeric parts are equal, then subtract the lengths.

const orig_array = ["2", "10", "01A", "1A", "02B", "1","03B"]; 
console.log(orig_array.sort((a,b)=>parseInt(a)-parseInt(b)||a.length-b.length));
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
  • I think the OP still wants to sort lexically, not by length, if the numeric prefixes match. – Bergi Nov 03 '21 at 02:13
  • 2
    Say in `01B` and `01A`, when the numeric parts are equal, don't you want to put the one with `A` before the one with `B`? Also, if there are no numeric parts, don't you compare the letters? – user1984 Nov 03 '21 at 02:13
  • 1
    @Bergi The expected result does not match with that. The code in the question is also subtracting the lengths, so it seems like it is a criteria. – Unmitigated Nov 03 '21 at 02:14
  • @Unmitigated `""` comes before `"A"` comes before `"B"` in a lexical sort, which is consistent with the expected `sorted_array`? OP also uses `a.localeCompare(b)` in his code (admittedly in a weird way). – Bergi Nov 03 '21 at 02:17
  • 1
    @Bergi Perhaps this one then: `orig_array.sort((a,b)=>parseInt(a)-parseInt(b)||a.replace(/^\d+/, '').localeCompare(b.replace(/^\d+/,''))||a.length-b.length)` – Unmitigated Nov 03 '21 at 02:19
  • @Unmitigated the above solution is working perfectly for the dataset that I have. Thanks a lot! – MSH Nov 03 '21 at 02:42