0

With Crystal, I can compare two numbers using the <==> operator. Example:

p! 1 <=> 1

Running this prints:

1 <=> 1 # => 0

The zero signifies that both numbers are equal. If the value is higher, it would return a positive number. If the value is lower, it returns a negative number. I'd like to know if such an operator exists with Python. Trying to use the <==> operator gives a syntax error:

>>> 1 <==> 1
File "<stdin>", line 1
1 <==> 1
    ^
SyntaxError: invalid syntax

I can obviously use something like this:

if 1 == 1:
   #equal
elif 1 < 1:
   #less than
else:
    #greater than

But I think it would be simpler to use a universal operator for comparing.

SuperStormer
  • 4,997
  • 5
  • 25
  • 35
dio
  • 112
  • 1
  • 13
  • 1
    No such operator exists, but you can trivially define a function for this use-case – juanpa.arrivillaga Jul 26 '21 at 18:50
  • Related: [Three-way comparing strings in Python 3](https://stackoverflow.com/questions/50782317/three-way-comparing-strings-in-python-3) – Brian61354270 Jul 26 '21 at 18:51
  • 2
    The pythonic equivalent would be the `cmp` function, however this only exists in python 2 and not python 3. See https://stackoverflow.com/questions/22490366/how-to-use-cmp-in-python-3 for python 3 alternatives. – SuperStormer Jul 26 '21 at 18:52
  • 3
    Languages that have this operator usually have a built-in sorting function that needs a 3-way result. Python doesn't have this type of sorting function, so it doesn't need the operator. – Barmar Jul 26 '21 at 18:53
  • you could just subtract the values! – ti7 Jul 26 '21 at 18:53
  • @ti7 That only works for numbers, not strings or other types. – Barmar Jul 26 '21 at 18:53
  • *Python **3** doesn't have this type of sorting function, so it doesn't need the operator. Python 2 used 3-way comparisons for sorting, which is why it had the `cmp` function. (Python 3 uses a key function instead) – SuperStormer Jul 26 '21 at 18:55
  • @Barmar that's fair, but they only ever make reference to numbers, and so may not be aware that they could even compare non-numerics (such as `"eggs"` and `"spam"`) or may want [Python's rich comparisons on custom objects](https://docs.python.org/3/reference/datamodel.html#object.__lt__), etc. (where often only `__it__` is needed to sort, etc.) – ti7 Jul 26 '21 at 18:56
  • @ti7 If you want to be pedantic, they used the specific number `1`, in which case it's silly to do a comparison at all. `1 < 1` can never be true. – Barmar Jul 26 '21 at 19:03
  • @Barmar ah, I mean that they only refer to comparing numbers , specifically _I can compare two numbers using the `<==>` operator_ – ti7 Jul 26 '21 at 19:12

2 Answers2

1

Even if you had such an operator, you still end up with the 3-way if:

if a <=> b == 0:
    # equal
elif a <=> b < 0:
    # less than
else:
    # greater than

so it doesn't really buy you much. It does mean you can avoid writing the comparison expression if it's complex:

compare = a <=> b
if compare == 0:
    ...

But that was apparently not useful enough for the Python designers to keep the built-in cmp() function that was in Python 2.x.

If you really want it, there are a number of implementations in How to use cmp() in Python 3?

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • "you still end up with the 3-way if" - not if i'm storing the value in a database – dio Dec 12 '21 at 21:45
0

To compare numbers and find out if they're greater or smaller in one go, you may be able to just use subtraction!

>>> 1-1
0
>>> 1-5
-4

However, if you wanted rich comparison, define __lt__ on a custom object

class Foo():
    def __init__(self, name, primary, secondary):
        self.name      = name
        self.primary   = primary
        self.secondary = secondary
    def __str__(self):
        return self.name
    def __repr__(self):
        return f"Foo({self})"
    def __lt__(self, other):
        base       = self.primary * 100 + self.secondary
        comparison = other.primary * 100 + other.secondary
        return base < comparison
>>> a = Foo("some A", 3,4)
>>> b = Foo("some other B", 2, 99)
>>> test = (a,b)
>>> test
(Foo(some A), Foo(some other B))
>>> sorted(test)
[Foo(some other B), Foo(some A)]
Carl Walsh
  • 6,100
  • 2
  • 46
  • 50
ti7
  • 16,375
  • 6
  • 40
  • 68
  • This would be good, but only for integers. I cannot compare strings like this. I guess my question didn't reflect that well. – dio Jul 26 '21 at 19:20
  • I was just chewing on the language spec, so it certainly wasn't obvious! .. still, you can use the rich comparison to compare anything (including comparing many different properties of your custom class individually with their own rich comparisons!) – ti7 Jul 26 '21 at 19:21
  • presumably there are many incomparable cases within crystal, even if it produces a result, for example sorting some non-homogenous collection, where you would need to define some custom comparator for each plausible case or let it fall back to identifier where the comparison isn't meaningful (like the memory address) – ti7 Jul 26 '21 at 19:26