-2

I have this array

const a = ['s2', 'sb', 's5', 's1', 'sc', 's3', 's4']

After sort I want to this result:

['sb', 'sc', 's1', 's2', 's3', 's4', 's5']

I tried use sort() but didnt work

newpluser
  • 19
  • 6
  • Hi @newpluser! Can you share some of the code you've tried and explain why that didn't work? – Robin James Kerrison Oct 13 '19 at 14:26
  • 1
    Do your strings always have length 2? What about `s10`? How should it be sorted? Please provide some edge cases. – trincot Oct 13 '19 at 14:32
  • @trincot no, s10 may exists, if s10 exists then for examlple should be ['sb', ...., 's5', 's10'] – newpluser Oct 13 '19 at 14:35
  • I tried sort() function – newpluser Oct 13 '19 at 14:36
  • You didn't answer how `s10` should be sorted with the rest. Please provide some edge cases. – trincot Oct 13 '19 at 14:39
  • @trincot sorry, I have edited my comment – newpluser Oct 13 '19 at 14:40
  • That is a mix of [natural sort](https://stackoverflow.com/questions/2802341/javascript-natural-sort-of-alphanumerical-strings) and a requirement that digits should come after letters. This is going to be cumbersome. Why do you want to deviate from the standard? – trincot Oct 13 '19 at 14:44
  • @trincot its not my idea :D 'sb' and 'sc' should be always on the begin of array, rest in numer order – newpluser Oct 13 '19 at 14:49
  • How complicated can these strings be? Can they be 100 characters long? What is the format? It might be easier to solve for a certain pattern than for the general case. Could the strings be *anything*? What about punctuation, non-latin, ... – trincot Oct 13 '19 at 14:53

2 Answers2

0

use String.match to get the chars after s, if the chars are numbers use a-b to sort else use localeCompare.

const a = ["s2","sb","s5","s1","sc","s3","s4","s100","s10","sz","san"];
a.sort(
  (a, b) => (a.match(/s(\d*)/)[1] - b.match(/s(\d*)/)[1]) || a.localeCompare(b)
);
console.log(a);
AZ_
  • 3,094
  • 1
  • 9
  • 19
  • The title of the question mentions letters and numbers, not 's' character specifically. – mutil Oct 13 '19 at 16:43
  • @mutil wordplay :) , but I considered all. – AZ_ Oct 13 '19 at 16:51
  • Array `['y1, 'za']` will throw `TypeError: Cannot read property '1' of null`. – mutil Oct 13 '19 at 17:01
  • where these come from? I think OP will have all elements starting with `s` else it won't make any sense. – AZ_ Oct 13 '19 at 17:04
  • As I said, the title is `... first with letter then with number`, strings starting with 's' may only be the example. – mutil Oct 13 '19 at 17:08
  • ohh, let OP confirm this rather assuming. I will update if he does not want this. – AZ_ Oct 13 '19 at 17:10
0

You can initially sort with localeCompare, and then by testing if number exists:

const a = ['s2', 'sb', 's5', 's1', 'sc', 's3', 's4', 's10', 'sa', 'sza', 's200', 's12', 's113'];
a.sort((a, b) => a.localeCompare(b, 'en', { numeric: true }))
 .sort((x, y) => (/[0-9]/g).test(x) - (/[0-9]/g).test(y));

console.log(a);
// ["sa", "sb", "sc", "sza", "s1", "s2", "s3", "s4", "s5", "s10", "s12", "s113", "s200"]
mutil
  • 3,205
  • 1
  • 27
  • 34
  • second sort will mess up the prior sorted data, as it just moves non alphanumeric first, whichever comes last goes first in merge sort but not in order. try with more data as `['s2', 'sb', 's5', 's1', 'sc', 's3', 's4', 's10', 'sa', 'sza', 's200', "s12", "s113"]` – AZ_ Oct 13 '19 at 15:34
  • @AZ_, I don't get it, what is the expected output with the array you mentioned? I get the exact same results as with your solution, except this one also works with first character other than 's'. – mutil Oct 13 '19 at 16:39