SKR123
SKR123

Reputation: 293

sorting javascript array on custom string condition

I have an array in the following format.

const arr = [{name:'11'},{name:'10'},{name:'9'},{name:'8'},{name:'7'}
{name:'6'},{name:'5'},{name:'4'},{name:'3'},{name:'2'},{name:'1'}
{name:'UN'},{name:'PG'},{name:'LN'},
{name:'12'},{name:'13'}]

I can sort it to get an output like below.

arr.sort((x, y)=> {
        if(x.name == 'LN' || x.name=='UN' || x.name== 'PG' || (parseInt(x.name)<parseInt(y.name))) {
          return -1;
        }
        return 0;
      })

Current Output : simplified for easy visualization

[LN,PG,UN,1,2,3,4,5,6,7,8,9,10,11,12,13]

I want PG to come after UN. Should do a swap like below after sorting or can it be done in the sort function it self?

[arr[1], arr[2]] = [arr[2],arr[1]]

Expected Output : simplified for easy visualization

[LN,UN,PG,1,2,3,4,5,6,7,8,9,10,11,12,13]

Upvotes: 0

Views: 52

Answers (2)

jsejcksn
jsejcksn

Reputation: 33786

Create a value map for the strings.

Also, when converting strings to number values, prefer the Number() constructor, as it is more strict than parseInt() and will help you avoid some potentially undesirable results.

const arr = [{name:'11'}, {name:'10'}, {name:'9'}, {name:'8'}, {name:'7'}, {name:'6'}, {name:'5'}, {name:'4'}, {name:'3'}, {name:'2'}, {name:'1'}, {name:'UN'}, {name:'PG'}, {name:'LN'}, {name:'12'}, {name:'13'}];

const result = arr.sort((oA, oB) => {
  // Handle case of same value:
  if (oA.name === oB.name) return 0;

  // Coerce to numbers:
  const nA = Number(oA.name);
  const nB = Number(oB.name);

  // Handle the case for two numbers:
  if (Number.isInteger(nA) && Number.isInteger(nB)) return nA - nB;

  // Handle the case for two non-numbers:
  if (Number.isNaN(nA) && Number.isNaN(nB)) {
    const valueMap = { LN: 0, UN: 1, PG: 2 };
    return valueMap[oA.name] - valueMap[oB.name];
  }

  // Handle the case for one number and one non-number:
  return Number.isNaN(nA) ? -1 : 1;
});

console.log(result);

Upvotes: 2

Keith
Keith

Reputation: 24211

One way is to give the name a rank,

Assuming your numbers are always positive, a really simple way to rank is use a lookup for the text, making them less than 0. If new name types appear in the future it's just a case of updating the rank lookup. You can then sort on this rank function.

eg..

const arr = [{name:'11'},{name:'10'},{name:'9'},{name:'8'},{name:'7'},
{name:'6'},{name:'5'},{name:'4'},{name:'3'},{name:'2'},{name:'1'},
{name:'UN'},{name:'PG'},{name:'LN'},
{name:'12'},{name:'13'}];

const ranks = {
  LN: -3,
  UN: -2,
  PG: -1
}

function rank(n) {
  if (ranks[n]) return ranks[n]
  else return Number(n);
}

arr.sort((a,b) => {
  return rank(a.name) - rank(b.name);
});

console.log(arr);

Upvotes: 4

Related Questions