0

I've met a problem recently with "double" sorting.

Here is an array : array = ['201-4', '201-2', '200-1', '202-1']

I need to sort this array by the first number (200,201,202) AND by the second number (1,2,4). I succeeded by doing array.sort((a,b) => Number(a.split('-')[1]) - Number(b.split('-')[1])) // here I sort by the second number array.sort((a,b) => Number(a.split('-')[0]) - Number(b.split('-')[0])) // then here I sort by the first number

The issue is that I find that a bit dirty doing two sort for a single array since I'll be working with much longer array in the future and this may cause performance issue. I was wondering if there is a much cleaner way to deal with that ?

Thanks for your help !

I expect the array to be sorted from ['201-4', '201-2', '200-1', '202-1'] to ['200-1', '201-2', '201-4', '202-1']

Kanad
  • 1
  • 2
    have you tried the following: `let data = ['201-4', '201-2', '200-1', '202-1'] console.log(data.sort())` – The KNVB Dec 14 '22 at 01:13
  • @Kanad, Will the first number ever be other than 3 digits e.g. "1058-1"? Also, will the second number ever be be other than 1 digit, e.g. "202-12". If either of your answers is YES, then you need to stick to Numeric sorting or refactor the strings to allow for the greatest number of digits in each section using leading zeros (e.g. "0201-02") after which case you can just use the string sort suggested by The KNVB. – Nikkorian Dec 14 '22 at 01:19
  • @TheKNVB Yes I did, the thing is that when I have this case : ['203-1','202-101','202-34'] it will sort as this : ['202-101','202-34','203-1']. I 202-101 must be after 202-34 – Kanad Dec 14 '22 at 01:20
  • @Nikkorian first number can be 3 to 4 digits and second number can go from 1 to 4 digits – Kanad Dec 14 '22 at 01:22
  • Once you get `array.map((string) => string.split("-").map(Number))`, refer to [How to sort an array of objects by multiple fields?](/q/46256174/4642212). It’s `.sort(([ leftA, rightA ], [ leftB, rightB ]) => leftA - leftB || rightA - rightB)`. Then join everything back together using `.map((array) => array.join("-"))`. `array.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))`, directly, seems to work, too. – Sebastian Simon Dec 14 '22 at 01:39

3 Answers3

0

As mentioned in the comments, if your numbers always have the same number of digits, you can just use .sort() with no parameters. If you need to treat them as numbers, you can do the sort as one nested set of comparisons:

array.map(i => i.split("-").map(j => parseFloat(j))).sort((a, b) => a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : (a[1] < b[1] ? -1 : (a[1] > b[1] ? 1 : 0)))).map(i => i.join("-"));

As suggested by hobbs, this can be simplified using Math.sign:

array.map(i => i.split("-").map(j => parseFloat(j))).sort((a, b) => Math.sign(a[0] - b[0]) || Math.sign(a[1] - b[1])).map(i => i.join("-"));
Benjamin Penney
  • 637
  • 3
  • 10
0

You don't have to stress yourself over this. only .sort() will do its work itself.

1. INPUT:

const array = ['201-4', '201-2', '200-1', '202-1'];

OUTPUT:

console.log(array.sort()); 
// Answer: [ "200-1", "201-2", "201-4", "202-1" ]

An snippet of the above code. An snippet of the above code.

2. If you want to treat it like a number you can do this.

array.map(e => Number(e.replaceAll('-','.'))).sort().map(e => e.toString().replaceAll('.','-'));

Example for above code treating as a number

  • The thing is that when I have this case : ['203-1','202-101','202-34'] it will sort as this : ['202-101','202-34','203-1']. I 202-101 must be after 202-34 – Kanad Dec 14 '22 at 01:23
0

Here's another approach (https://jsfiddle.net/w8Lrezsk/):

let data = ['201-4', '201-102', '200-1', '202-1'];
let max = 10;
let sortdata = [];
data.forEach((val)=>{
    let valarray = val.split('-');
    let newstr = valarray[0].padStart(max,'0')+"-"+valarray[1].padStart(max,'0');
    sortdata.push(newstr)
});
sortdata.sort();
data = [];
sortdata.forEach((val)=>{
    valarray = val.split('-');
    valarray[0] = valarray[0].replace(/^0+/, '');
    valarray[1] = valarray[1].replace(/^0+/,'');
    data.push(valarray[0]+'-'+valarray[1]);
});
console.log(data);
Nikkorian
  • 770
  • 4
  • 10