2

I have an array of objects like so for example:

[ {
    id: '-1'
},
{
    id: '10'
},
{
    id: '1234'
},
{
    id: '1235'
},
{
    id: '-1'
} ]

I would like to sort this array so that it is ordered by the ids ascending (smallest to largest), however I would like objects that have the id of '-1' to be sent to the back of the array. So I tried this:

const arr = [ {	id: '-1' }, { id: '10'}, { id: '1234' }, { id: '1235' }, { id: '-1' } ]
arr.sort((a, b) => {
	if (parseInt(a.id) === -1 || parseInt(b.id) === -1) return 1;
	if (parseInt(a.id) - parseInt(b.id)) return -1;
});
console.log(arr);

As you can see from the snippet above it sorts them successfully ascending however it doesn't successfully move ids with '-1' to the back of the array.

Why does this happen? What am I doing wrong?

3
  • Why can't you sort in ascending order without worrying about -1. All the other numbers seem to be bigger than 0, so -1 will naturally be the smallest and gather at the start of the array? :) Commented Jul 22, 2018 at 9:59
  • @Max I'm more or less using this to sort data and display it. I don't explicitly want to sort smallest to biggest so that's why I didn't do that. Commented Jul 22, 2018 at 10:09
  • Ah, I also read "back of the array" as "begging" rather than "end" Commented Jul 22, 2018 at 10:15

2 Answers 2

3

You could take the function with a check for the items which should be sorted to bottom.

var array = [{ id: '-1' }, { id: '10' }, { id: '1234' }, { id: '1235' }, { id: '-1' }];

array.sort((a, b) => (a.id === '-1') - (b.id === '-1') || a.id - b.id);

console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

Comments

1

How sorting works

First, let's take a look at what .sort expects you to feed it.

Given paramaters (a, b) -- we should return

  • < 0 if a < b
  • > 0 if a > b

How you did the sorting

Let's take a look at your first line

if (parseInt(a.id) === -1 || parseInt(b.id) === -1) return 1;

-1 means "a is smaller". But that might not be true. It might be that a (not b) is -1, and is bigger, yet we're always telling JavaScript to send a to the back when that's what we should be doing to b.

Instead, we want to return -1 when b is -1, but +1 when a is -1. It doesn't really matter what we return if they're both -1.



In JavaScript, any number except for 0 is truthful. Let's take a look at your next line.

if (parseInt(a.id) - parseInt(b.id)) return -1;

If a - b is 0, we don't return anything in this callback. If it isn't 0, we always say that a < b.

Notice that never do we say that b < a -- so if such an event were to occur, we couldn't handle it and would sort it incorrectly.

How to sort correctly

Fetch IDs

const aID = parseInt(a.id)
const bID = parseInt(b.id)

Is a or b -1?

if(aID === -1) return +1;
if(bID === -1) return -1;

Which is bigger, a or b

If you assume that a and b are not -1, then we can simply subtract a - b. Why? If a is bigger than b, then the subtraction will create a positive number to say b < a. If a is less than b, then the subtraction will create a negative number, to say a < b.

return aID - bID

All together

const arr = [ {	id: '-1' }, { id: '10'}, { id: '1234' }, { id: '1235' }, { id: '-1' } ]
arr.sort((a, b) => {
	const [aID, bID] = [parseInt(a.id), parseInt(b.id)]
  if(aID === -1) return +1
  if(bID === -1) return -1
  return aID - bID
});
console.log(arr);

Golfing

It might be helpful to make things shorter. Another answer, by @Nina Scholz, helpfully showed a much shorter version. I thought it might be useful to explain why this works.

return (a.id === '-1') - (b.id === '-1') || a.id - b.id

What is x || y

x || y means:

  • if x is truthful, return x.
  • if x isn't truthful, return y.

What is (aID === -1)

This means true if aID is -1, and false otherwise

What is (aID === -1) - (bID === -1)

How can you subtract true and false? true will be interpreted as 1, and false as 0.

aID = -1, bID = not

This value will be 1 - 0, or +1

aID = not, bID = -1

This value will be 0 - 1, or -1

aID = -1, bID = -1

Remember, it doesn't matter what we return if the two values are the same

aID = not, bID = not

0 - 0. This is 0. This is not a truthful value. So we go into the || bit. Which, in that answer, has the second bit be aID - bID, as described above. It's very clever and very short, though might not be as readable.

2 Comments

Thank you very much Max for the detailed answer! Learnt a lot from this :)
Thanks! I thought I'd add some information about the old accepted answer, in case you find that useful.

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.