Combined Comparison / "Spaceship" Operator (<=>) in Javascript?
Asked Answered
P

3

35

Ruby has something called a Combined Comparison or "Spaceship" Operator, it looks like this: <=>

It does the following:

a <=> b :=
    if a < b then return -1
    if a = b then return  0
    if a > b then return  1

Credit

Is there a similar Operator in Javascript? If not, how can I end up with the same result?


@madox2 suggested using Math.sign(a - b), which works for number, but not arrays (to compare arrays you need to use array.length).

It also does not work in Internet Explorer, Safari or all Mobile Browsers (see MDN)


@duques_l found a function here. It works very well, you can test it on JSFiddle

The only problem is if the strings are not comparable the function returns -1 instead of nil

Update: @duques_l changed the function a bit and now it works fine (I think so anyway, here is the JSFiddle):

function spaceship(val1, val2) {
    if ((val1 === null || val2 === null) || (typeof val1 != typeof val2)) {
        return null;
    }
    if (typeof val1 === 'string') {
        return (val1).localeCompare(val2);
    }
    else {
        if (val1 > val2) { return 1 }
        else if (val1 < val2) { return -1 }
        return 0;
    }
}

Premonition answered 18/1, 2016 at 10:49 Comment(2)
doesn't exist, but sabrelabs.com/post/48201437312/javascript-spaceship-operatorAcrimony
@duques_l Interesting link. That function does seem to do just that!Premonition
F
39

As far as I know there is no such operator in JavaScript but you can use Math.sign() function:

Math.sign(a - b);

NOTE: As was mentioned in comments, Math.sign() is not currently supported by all browsers. Check for compatibility (MDN).

Finned answered 18/1, 2016 at 10:51 Comment(7)
This works for numbers, but not arrays (well, you have to use array.length). Clever solution though!Premonition
if there is one, not in ie.Judicator
@NinaScholz If there is one what?Premonition
@Druzion, the Internet Explorer does not have Math.sign().Judicator
@NinaScholz Ah yes, it is also not supported in Safari and all Mobile Browsers, according to MDNPremonition
As of today and according to CanIUse.com : Math.sign is supported by almost 95% browsers. If your target clients is that guys who update their browsers, you can assume it's now safe to use it.Keelby
For those desperate to support Legacy Browsers: if(!Math.sign) Math.sign=function(value) {return value?(value<0?-1:1):0}; will do for a polyfill.Craftsman
J
9

from: http://sabrelabs.com/post/48201437312/javascript-spaceship-operator

improved version:

function spaceship(val1, val2) {
  if ((val1 === null || val2 === null) || (typeof val1 != typeof val2)) {
    return null;
  }
  if (typeof val1 === 'string') {
    return (val1).localeCompare(val2);
  } else {
    if (val1 > val2) {
      return 1;
    } else if (val1 < val2) {
      return -1;
    }
    return 0;
  }
}
Jeanelle answered 18/1, 2016 at 11:36 Comment(4)
No, if the data types are different, it returns 0. Check the new JSFiddlePremonition
it's fixed, can you check ?Acrimony
nil doesn't exist in javascript, it's nullAcrimony
I think that function is a bit over-engineered lolMisology
D
2

Here is a one-liner for current js ES2020?:

const spaceship = (a, b) => (a ?? 0).toString().localeCompare((b ?? 0).toString());

Returns string comparison for everything.

Decastere answered 25/10, 2021 at 17:29 Comment(2)
As this uses string comparison for numbers, it can give invalid results for inputs with a different quantity of digits, e.g. spaceship(100, 2) will result in -1 (as it's effectively sorting alphabetically and the first "letter", 1 is "less" than 2)Knuth
As this uses string comparison for everything, objects and arrays will not sort... as their string representation will be '[object Object]' and that is equal to itself. 0 is neither -1 or 1.Decastere

© 2022 - 2024 — McMap. All rights reserved.