Home > Blockchain >  JS: Sort a part of an array by order
JS: Sort a part of an array by order

Time:12-01

I have a task to sort an array of random numbers by a certain order which is given from another array. All the other elements which could not be sorted should land at the end of the result array:

const array = [6,1,2,3,4,5]
const sortOrder = [3,2,1]
const shouldSortTo = [3,2,1,6,4,5]

I've got the following solution :

array.sort((a,b)=> {
  if(sortOrder.indexOf(a) === -1 && sortOrder.indexOf(b) > -1 ) {
    return 1  
  }
  if(sortOrder.indexOf(a) > -1 && sortOrder.indexOf(b) === -1 ) {
    return -1
  }
  return sortOrder.indexOf(a) - sortOrder.indexOf(b) 
})

It works but I get the feeling that it's not easy to read or understand. Is there a better or shorter way to do it?

CodePudding user response:

Not saying this is better or more efficient but you can first check if all sortOrder items are in the array, then remove sortOrder items from array and concat the two:

const array = [6,1,2,3,4,5]
const sortOrder = [3,2,1]
const shouldSortTo = [3,2,1,6,4,5]

let result = sortOrder.filter(s => array.includes(s)).concat(array.filter(i => !sortOrder.includes(i)))

console.log(result)
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

Edit: Based on @epascarello's comment, this may be a better option if array contains duplicate values:

const array = [6,1,2,3,4,5,2,3]
const sortOrder = [3,2,1]

let sorted = sortOrder.reduce((s, i) => [...s, ...array.filter(x => x === i)], [])
let result = sorted.concat(array.filter(i => !sortOrder.includes(i)))

console.log(result)
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

I would not keep lookin up the index. Just read it once and use it. You can apply it to your own code.

const array = [6,1,2,3,4,5]
const sortOrder = [3,2,1]

array.sort((a,b)=> {
  const aI = sortOrder.indexOf(a);
  const bI = sortOrder.indexOf(b);

  if (aI === -1 && bI > -1 ) return 1;
  else if (aI > -1 && bI === -1 ) return -1;
  return aI - bI; 
})


console.log(array);
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

I would check if they are both equal and return zero. I would check for either to be -1. And finally I would sort base on the index.

const array = [6,1,2,3,4,5]
const sortOrder = [3,2,1]

array.sort((a,b)=> {
  const aI = sortOrder.indexOf(a);
  const bI = sortOrder.indexOf(b);

  if (aI === bI) return 0;
  else if (aI === -1) return 1;
  else if (bI === -1) return -1;
  else return aI - bI;
})

console.log(array);
<iframe name="sif4" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

Other option, if -1, set to the array's length and just subtract

const array = [6,1,2,3,4,5]
const sortOrder = [3,2,1]

const max = array.length;
array.sort((a,b)=> {
  const aI = sortOrder.indexOf(a);
  const bI = sortOrder.indexOf(b);

  return (aI === -1 ? max : aI) - (bI === -1 ? max : bI);
})

console.log(array);
<iframe name="sif5" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

Or you can reserve the logic

const array = [6,1,2,3,4,5]
const sortOrder = [3,2,1]

const max = array.length;
const reversed = sortOrder.slice().reverse();
array.sort((a,b)=> {
  const aI =  max - reversed.indexOf(a);
  const bI =  max - reversed.indexOf(b);
  return aI - bI;
})

console.log(array);
<iframe name="sif6" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related