[SUMMARY] Price ranges (#164)

Discussion in 'Ruby' started by Matthew Moss, Jun 5, 2008.

  1. Matthew Moss

    Matthew Moss Guest

    In this quiz, James presented us with a practical problem that is
    quite common in everyday life. Sometimes we make such decisions
    implicitly and "fuzzily", when we shop at a particular store since
    another shop "is too expensive." Other times it is a more explicit
    search, such as when filtering online listings for products, rentals,
    or other services.

    The quiz boils down to determining which providers' price ranges
    overlap that of the consumer's desired range. To test whether range A
    and B overlap requires that at least one of the following hold:

    * At least one endpoint (i.e. low or high price) of range A falls
    within range B.
    * At least one endpoint of range B falls within range A.

    A pretty simple task with a good amount of repetitive behavior, which
    suggests that these behaviors should be consolidated.

    We'll take a look at _Chris Shea_'s solution: it's simple, well-
    documented and easy code to read in use. Chris defines a new class,
    `PriceRange`, rather than use the built-in `Range` class. This seems
    appropriate, as the class is not intended to be reused in the same
    manner as `Range`. Let's first look at the initializer:

    def initialize(opts={})
    @low = opts[:low] || 0
    @high = opts[:high] || 1.0 / 0.0
    end

    The use of a hash as the initialization parameter allows Chris to make
    use of `PriceRange` like this:

    customer = PriceRange.new:)low => 2_500, :high => 5_000)

    And in fact, one or both of `:low` and `:high` could be left out to
    create open-ended or empty ranges. Even reordering them is fine, as
    they are no longer parameters but rather a single hash.

    The initializer remembers the low and high values, providing defaults
    if necessary: zero for the low end of the range, and `1.0 / 0.0` --
    that is, Infinity, with a capital *I*. Infinity is a constant of class
    Float that is greater than all other numbers. So it serves as a valid,
    and quite convenient, high value for an open-ended range.

    To check for basic overlap, Chris defines these methods:

    def includes_price?(price)
    price >= @low and price <= @high
    end

    def includes_edge_of?(other)
    includes_price?(other.low) or includes_price?(other.high)
    end

    Very straightforward. As mentioned above, determining if two ranges
    overlap involves two parts, where `includes_edge_of?` satisfies one of
    those parts (here, *a* and *b* are `PriceRange` instances):

    a.includes_edge_of?(b)

    To perform the whole overlap check, then, is simply a matter of also
    doing the reverse check, and using the logical-or operator to combine:

    a.includes_edge_of?(b) or b.includes_edge_of?(a)

    And that is exactly what we see in the last method of the `PriceRange`
    class, `select`, but checking over all provided `PriceRange`
    arguments:

    def select(*ranges)
    ranges.select { |range|
    self.includes_edge_of?(range) or range.includes_edge_of?
    (self)
    }
    end

    I like the simplicity of the code as well as the readability (as shown
    by example in the code's comments). My only possible complaint is a
    preference to use a named constant for infinity in the code, though it
    would seem that inserting `(1.0 / 0.0)` is the easiest way to get such
    constant.
     
    Matthew Moss, Jun 5, 2008
    #1
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Michael Gallen
    Replies:
    0
    Views:
    491
    Michael Gallen
    Dec 5, 2003
  2. Nandhu
    Replies:
    0
    Views:
    461
    Nandhu
    Dec 4, 2007
  3. dkjena1
    Replies:
    1
    Views:
    1,880
    joris
    Jun 8, 2011
  4. Matthew Moss

    [QUIZ] Price Ranges (#164)

    Matthew Moss, May 31, 2008, in forum: Ruby
    Replies:
    14
    Views:
    196
    Matthew Rudy Jacobs
    Jun 7, 2008
  5. Martina
    Replies:
    2
    Views:
    145
    Anno Siegel
    Sep 10, 2005
Loading...

Share This Page