Hacker News new | ask | show | jobs
by nemo1618 2754 days ago
Ha, I've been using this trick for a while, though I wouldn't go so far as to say "don't use the greater-than-sign." Honestly I just wish languages had a cleaner way to write "x is within this range," e.g. "if x in [2,4)"
4 comments

SQL has "x between 2 and 4" (for example) which is a lot clearer.
or x not between 2 and 4
In Python we have if 2 <= x < 4.
There's also `if x in range(2,4)`, which translates to `if x in the interval [2, 4)`.
Is this efficient? I was under the impression (which is likely inaccurate, because I'm no expert on Python) that range returned a generator or a list outright, making this an O(n) operation.
You're correct. It returns a list from from [a, b), but it's just another example of some expressive (albeit computationally inefficient) notation Python has.

Edit: I take that back. Here's a section from Python's range() documentation:

> The advantage of the range type over a regular list or tuple is that a range object will always take the same (small) amount of memory, no matter the size of the range it represents (as it only stores the start, stop and step values, calculating individual items and subranges as needed).

So it may be a O(1) operation under the hood.

No, what the docs say is that range is a generator. It never stores the entire list of values, but it does iterate through all the numbers, spitting them out one by one (hence it uses O(1) memory, but O(n) computation).

Equivalent pseudocode:

  function in_range(x, a, b):
    for i=a; i<b; i++:
      if x == i return true
    return false
That... has nothing to do with nemo1618's wish. The python statement 2 <= x < 4 is not a statement about x being within a particular range; it's just as valid to say 2 <= x > 4.
Nobody would ever purposefully write 2 <= x > 4 … it's a bug. Maybe if the bounds on the example were variable.

But the point of being able to collapse a < b and b < c into a < b < c is there to make ranges easier to notate/read. That's seems to be nemo's wish. (Though perhaps he wishes the range to be completely separate, e.g., in the psuedosyntax `b in [1, 3)`.)

I don't think I've ever seen it actually used for anything else, and I would in advocate against it, in code review.

> I don't think I've ever seen it actually used for anything else, and I would in advocate against it, in code review.

Yes, this would be a terrible practice. But that's what Python offers. The desire to express that a variable's value lies within a range is very common, and is presumably the reason for Python's bad choice. But that doesn't make Python's syntax a good response to the desire. The syntax expresses a conceptual mess; you're relying on people only using a tiny subset of what's there.

Contrast lisp, where you actually can express the concept of a range, as (< lowBound variable highBound). Unfortunately, that won't allow you to mix soft bounds with strict bounds. But it's vastly better than Python's approach.

Contrast Ruby, which offers almost every convenience in ranges, including literal notations, that you could ask for.

Swift has it. I'm sure a few languages must have it.

    if (2...4).contains(x)
This doesn't work for me:

  $ swift
  Welcome to Apple Swift version 4.2.1 (swiftlang-1000.11.42 clang-1000.11.45.1). Type :help for assistance.
    1> let x = 3
  x: Int = 3
    2> if x in 2...4 {}
  error: repl.swift:2:6: error: expected '{' after 'if' condition
  if x in 2...4 {}
       ^
Are you sure you didn't mean to use if case?

  if case 2...4 = x
Yeah, I was wrong. I updated my comment. I think I just meant to check if a range contains a value, as I changed it to.
You can use ~= if you're looking for a succinct way to do an operation like this:

  if 2...4 ~= x
I didn't know about this. Brilliant, cheers!
Does that work for floats?
Yes, if you use the pattern matching operator I suggested to the original comment's author:

  $ swift
  Welcome to Apple Swift version 4.2.1 (swiftlang-1000.11.42 clang-1000.11.45.1). Type :help for assistance.
    1> let x = 3
  x: Int = 3
    2> let y = 3.0
  y: Double = 3
    3> 2...4 ~= x
  $R0: Bool = true
    4> 2...4 ~= y
  $R1: Bool = true
Floats that aren’t equivalent to ints: 2.5.

In some languages, similar constructs test membership in a list/range, rather than an inequality.

In C# this would be easy to implement using an extension method. Not a bad idea actually.