4

I have a string array as below.

let arr = ["1", "1+", "1-","2", "2+", "3","3+", "2-", "3-", "4", "10"];

I want the expected output as below.

["1+", "1", "1-", "2+", "2", "2-", "3+", "3", "3-", "4", "10"];

I tried the below code but it is not giving me the correct result.

let arr = ["1", "1+", "1-","2", "2+", "3","3+", "2-", "3-", "4", "10"];
let result = arr.sort((a,b) => { 
  return a.localeCompare(b, undefined, {
      numeric: true,
      sensitivity: 'base',
    });
  });

console.log(result);

3 Answers 3

3

So, you need comparator for numbers and for signs.

Gerenal concept:
You can define sign priority like this:

const signPriority = {
  '+': 0,
  'n': 1, // n = no sign
  '-': 2,
} 

Where key is sign and value is sign weight we will use in comparator ('n' means "no sign").

Then we will split up array elements to number and sign, in comparator function and comparate them separetely:

arr.sort((a, b) => { 
    // If numbers are different ...
    if (parseInt(a) !== parseInt(b)) {
        // Just compare a numbers 
        return parseInt(a) - parseInt(b);
    } else {
        // If sign matter ...
        // Extract sign from element or define as 'n' if no sign found
        const sign_a = ['+', '-'].includes(a.slice(-1)) ? a.slice(-1) : 'n';
        const sign_b = ['+', '-'].includes(b.slice(-1)) ? b.slice(-1) : 'n';
        // Compare signs using their weight
        return signPriority[sign_a] - signPriority[sign_b];
    } 
})

Full solution:

const signPriority = {
    '+': 0,
    'n': 1,
    '-': 2,
} 

const arr = ["1", "1+", "1-","2", "2+", "3","3+", "2-", "3-", "4", "10"];

const sorted = arr.sort((a, b) => { 
    if (parseInt(a) !== parseInt(b)) {
        return parseInt(a) - parseInt(b);
    } else {
        const sign_a = ['+', '-'].includes(a.slice(-1)) ? a.slice(-1) : 'n';
        const sign_b = ['+', '-'].includes(b.slice(-1)) ? b.slice(-1) : 'n';
        return signPriority[sign_a] - signPriority[sign_b];
    } 
})

console.log(sorted);

1
  • 3
    I'd say the .include() + .slice() is not really needed. signPriority[x.slice(-1)] ?? 0 will either give you the priority or zero. And for signPriority you only need { '+': -1, '-': 1 } If you wish to encode the default/no priority in the lookup, then you can use ` { '+': -1, '-': 1, default: 0 } with signPriority[x.slice(-1)] ?? signPriority.default
    – VLAZ
    Commented Feb 7, 2022 at 9:22
0

Split each string using a regex word boundary. Use destructuring to get the number in string form (an, bn), and the sign (as, bs). If the sign is undefined use a comma as a fallback, since comma falls between + and - in the ascii table.

The return value should be an - bn (difference of auto-casted numbers), and if that is 0 then use bs?.localeCompare(as) to sort by the sign.

const arr = ["1", "1+", "1-","2", "2+", "3","3+", "2-", "3-", "4", "10"];

const getNumAndSign = str => str.split(/\b/)

const sorted = arr.sort((a, b) => {
  const [an, as = ','] = getNumAndSign(a)
  const [bn, bs = ','] = getNumAndSign(b)
  
  return +an - +bn || bs?.localeCompare(as)
})

console.log(sorted);

-1

You should try convert string to decimal number and then compare. For example if you convert "2+" to 1.9 and "2-" to 2.1 then you can compare values as a numbers.

const arr = ["1", "1+", "1-","2", "2+", "3","3+", "2-", "3-", "4", "10"];

function convertToNumber(text) {
    const offset = text.endsWith("+") ? -0.1 : text.endsWith("-") ? 0.1 : 0;
    if (text.endsWith("+") || text.endsWith("-")) {
        text = text.substring(0, text.length - 1);
    }
    return parseFloat(text) + offset;
}

const sorted = arr.sort((a, b) => {
    return convertToNumber(a) > convertToNumber(b);
});
console.log("Sorted: ", sorted);

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.