UPDATE Feb 4, 2022 Yes, as commenter Matthias pointed out, you can let JavaScript implicitly make the conversion of boolean minus boolean to end number a number of -1, 0, or 1.
Original but edited blog post below...
Imagine you have an array like this:
const items = [
{ num: 'one', labels: [] },
{ num: 'two', labels: ['foo'] },
{ num: 'three', labels: ['bar'] },
{ num: 'four', labels: ['foo'] },
{ num: 'five', labels: [] },
];
What you want, is to sort them in a way that all those entries that have a label foo
come first, but you don't want to "disturb" the existing order. Essentially you want this to be the end result:
{ num: 'two', labels: ['foo'] }, { num: 'four', labels: ['foo'] }, { num: 'one', labels: [] }, { num: 'three', labels: ['bar'] }, { num: 'five', labels: [] },
Here's a way to do that:
items.sort(
(itemA, itemB) =>
itemB.labels.includes('foo') - itemA.labels.includes('foo')
);
console.log(items);
And the outcome is:
[ { num: 'two', labels: [ 'foo' ] }, { num: 'four', labels: [ 'foo' ] }, { num: 'one', labels: [] }, { num: 'three', labels: [ 'bar' ] }, { num: 'five', labels: [] } ]
The simple trick is to turn then test operation into a number (0 or 1) and you can do that with Number
.
Boolean minus boolean is operator overloaded to become an integer. From the Node repl...
> true - false 1 > false - true -1 > false - false 0 > true - true 0
Comments
Hi there!
Instead of using Number() on both includes-results, you can just use "itemB.labels.includes('foo') - itemA.labels.includes('foo')".
This works because minus will convert both sides to a number anyway before subtracting.
Best regards
You're right! I had forgotten about that. I updated the blog post.
Truth be told, I'm not sure it's an improvement because it feels like a quirk whereas casting to a number type feels a bit more "commonstream".