0

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?

2 Answers 2

1

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);

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);

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);

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);

Sign up to request clarification or add additional context in comments.

Comments

1

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)

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)

2 Comments

Only downside to this approach is it has to be a 1 to 1 or it fails. If the input can be const array = [6,1,2,3,4,5,2, 3] this would not work.
Very good point @epascarello! I will keep the answer but this should be the disclaimer :)

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.