0

I am trying to arrange given values in ascending orders

const value = [
  { val: "11-1" },
  { val: "12-1b" },
  { val: "12-1a" },
  { val: "12-700" },
  { val: "12-7" },
  { val: "12-8" },
];

I am using code below to sort this in ascending order:

value.sort((a,b)=>(a.val >b.val)? 1:((b.val>a.val)?-1:0));

The result of this sort is in the order 11-1,12-1a, 12-1b, 12-7, 12-700, 12-8. However, I want the order to be 11-1,12-1a, 12-1b, 12-7, 12-8, 12-700.

How can I achieve that?

MR AND
  • 376
  • 7
  • 29
  • 1
    You need to split each value at `-`, then parse the second element in the resulting array into integer and compare those numbers. – tromgy Mar 27 '22 at 15:40
  • 2
    ... and if you have also values like 10-333, 11-43, etc. you may want to combine the split values into a float and compare those floats. – tromgy Mar 27 '22 at 15:44
  • sorry for the confusion, i am supposed to handle string as well in this sort – MR AND Mar 27 '22 at 16:10

6 Answers6

2

If you're only interested of sorting by the value after the hyphen you can achieve it with this code:

const value = [
  
  {val:'12-1'},
  {val:'12-700'},
  {val:'12-7'},
  {val:'12-8'},

];

const sorted = value.sort((a,b) => {
  const anum = parseInt(a.val.split('-')[1]);
  const bnum = parseInt(b.val.split('-')[1]);
  return anum - bnum;
});

console.log(sorted);
Christian
  • 7,433
  • 4
  • 36
  • 61
1

updated the answer as your question update here's the solution for this:

const value = [{ val: '11-1' }, { val: '12-1b' }, { val: '12-1a' }, { val: '12-700' }, { val: '12-7' }, { val: '12-8' }];
const sortAlphaNum = (a, b) => a.val.localeCompare(b.val, 'en', { numeric: true });
console.log(value.sort(sortAlphaNum));
Abbas Hussain
  • 1,277
  • 6
  • 14
0

You can check the length first and then do the sorting as follow:

const value = [
  { val: "12-1" },
  { val: "12-700" },
  { val: "12-7" },
  { val: "12-8" },
];
const result = value.sort(
    (a, b)=> {
        if (a.val.length > b.val.length) {
            return 1;
        }
        if (a.val.length < b.val.length) {
            return -1;
        }
        return (a.val >b.val) ? 1 : ((b.val > a.val) ? -1 : 0)
    }
);
console.log(result);
Ashok
  • 2,411
  • 1
  • 13
  • 23
0

Since you are sorting on string values, try using String.localeCompare for the sorting.

Try sorting on both numeric components of the string.

const arr = [
  {val:'12-1'},
  {val:'11-900'},
  {val:'12-700'},
  {val:'12-7'},
  {val:'11-1'},
  {val:'12-8'},
  {val:'11-90'},
];
const sorter = (a, b) => {
  const [a1, a2, b1, b2] = (a.val.split(`-`)
    .concat(b.val.split(`-`))).map(Number);
  return a1 - b1 || a2 - b2; };
  
console.log(`Unsorted values:\n${
  JSON.stringify(arr.map(v => v.val))}`);
console.log(`Sorted values:\n${
  JSON.stringify(arr.sort(sorter).map(v => v.val))}`);
KooiInc
  • 119,216
  • 31
  • 141
  • 177
  • As per the requirements, the "12-700" should be after "12-8", i.e. the string with bigger length should be at end, which cannot be achived by using `localeCompare`. – Ashok Mar 27 '22 at 15:37
  • @Ashok It *can* be done using `localeCompare` as per [Abbas Hussains excellent answer](https://stackoverflow.com/a/71638298/58186). I deviced a more numeric solution though. – KooiInc Mar 28 '22 at 10:05
0

If you want to check for different values both before and after the hyphen and include checking for letters, the solution at the end will solve this.

Here's what I did:

Created a regex to split the characters by type:

var regexValueSplit = /(\d+)([a-z]+)?-(\d+)([a-z]+)?/gi;

Created a comparison function to take numbers and letters into account:

function compareTypes(alpha, bravo) {
  if (!isNaN(alpha) && !isNaN(bravo)) {
    return parseInt(alpha) - parseInt(bravo);
  }
  return alpha > bravo;
}

Split the values based on regexValueSplit:

value.sort((a, b) => {
  let valuesA = a.val.split(regexValueSplit);
  let valuesB = b.val.split(regexValueSplit);

This produces results as follows (example string "12-1a"):

[
  "",
  "12",
  null,
  "1",
  "a",
  ""
]

Then, since all the split arrays should have the same length, compare each value in a for loop:

  for (let i = 0; i < valuesA.length; i++) {
    if (valuesA[i] !== valuesB[i]) {
      return compareTypes(valuesA[i], valuesB[i]);
    }
  }
  // Return 0 if all values are equal
  return 0;

const value = [{
    val: "11-1"
  },
  {
    val: "12-1b"
  },
  {
    val: "12-1a"
  },
  {
    val: "12-700"
  },
  {
    val: "12-7"
  },
  {
    val: "12-8"
  },
];
var regexValueSplit = /(\d+)([a-z]+)?-(\d+)([a-z]+)?/gi;

function compareTypes(alpha, bravo) {
  if (!isNaN(alpha) && !isNaN(bravo)) {
    return parseInt(alpha) - parseInt(bravo);
  }
  return alpha > bravo;
}
value.sort((a, b) => {
  let valuesA = a.val.split(regexValueSplit);
  let valuesB = b.val.split(regexValueSplit);
  for (let i = 0; i < valuesA.length; i++) {
    if (valuesA[i] !== valuesB[i]) {
      return compareTypes(valuesA[i], valuesB[i]);
    }
  }
  return 0;
});
console.log(JSON.stringify(value, null, 2));
phentnil
  • 2,195
  • 2
  • 14
  • 22
0

little change's to @Christian answer it will sort before and after - value

const value = [{ val: '12-1' }, { val: '12-700' }, { val: '11-7' }, { val: '12-8' }];

const sorted = value.sort((a, b) => {
  const anum = parseInt(a.val.replace('-', '.'));
  const bnum = parseInt(b.val.replace('-', '.'));
  return anum - bnum;
});

console.log(sorted);
Abbas Hussain
  • 1,277
  • 6
  • 14