tags:

views:

181

answers:

3

I need a structure to hold a value based on a key that has a range. My implementation is C++, so any STL or Boost would be excellent.

I have as range-key, which are doubles, and value

  • [0,2) -> value1
  • [2,5) -> value2
  • [5,10) -> value3
  • etc

Such that a search of 1.23 should return value1, and so on.

Right now I am using a vector containing all three parts, key1/key2/value, with custom searching, but it feels like there should be a cleaner structure.

Edit: Thanks all. Given the ranges in this case are supposed to be contiguous and non-overlapping, the use of upper_bound will work just fine. Thanks for the class Range solutions as well, they are filed away for future reference.

+1  A: 

If your ranges are contiguous and non-overlapping, you should use std::map and the upper_bound member function. Or, you could use a sorted vector with the upper_bound algorithm. Either way, you only need to record the lowest value of the range, with the upper part of the range being defined by the next higher value.

Edit: I phrased that confusingly, so I decided to provide an example. In coding the example, I realized you need upper_bound instead of lower_bound. I always get those two confused.

typedef std::map<double, double> MyMap;
MyMap lookup;
lookup.insert(std::make_pair(0.0, dummy_value));
lookup.insert(std::make_pair(2.0, value1));
lookup.insert(std::make_pair(5.0, value2));
lookup.insert(std::make_pair(10.0, value3));
MyMap::iterator p = lookup.upper_bound(1.23);
if (p == lookup.begin() || p == lookup.end())
    ...; // out of bounds
assert(p->second == value1);
Mark Ransom
Wouldn't that be, "with the upper part of the range being defined by the next lower value."?
Nick Presta
+1  A: 
class Range
{
public:
    Range( double a, double b ):
        a_(a), b_(b){}
    bool operator < ( const Range& rhs ) const
    {
        return a_ < rhs.a_ && b_ < rhs.b_;
    }
private:
    double a_;
    double b_;
};
int main()
{
    typedef std::map<Range, double> Ranges;
    Ranges r;

    r[ Range(0, 2) ] = 1;
    r[ Range(2, 5) ] = 2;
    r[ Range(5, 10) ] = 3;

    Ranges::const_iterator it1 = r.find( Range( 2, 2 ) );
    std::cout << it1->second;

    Ranges::const_iterator it2 = r.find( Range( 2, 3 ) );
    std::cout << it2->second;

    Ranges::const_iterator it3 = r.find( Range( 6, 6 ) );
    std::cout << it3->second;

    return 0;
}
Mykola Golubyev
A: 

How about something along these lines:

#include "stdafx.h"
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <sstream>


class Range
{
public:
    Range(double lower, double upper) : lower_(lower), upper_(upper) {};
    Range(const Range& rhs) : lower_(rhs.lower_), upper_(rhs.upper_) {};
    explicit Range(const double & point) : lower_(point), upper_(point) {};
    Range& operator=(const Range& rhs) 
    { 
     lower_ = rhs.lower_; 
     upper_ = rhs.upper_; 
     return * this; 
    }

    bool operator < (const Range& rhs) const
    {
     return upper_ <= rhs.lower_;
    }

    double lower_, upper_;
};

typedef std::string Thing;
typedef std::map<Range, Thing> Things;


std::string dump(const std::pair<Range,Thing> & p)
{
    stringstream ss;
    ss << "[" << p.first.lower_ << ", " << p.first.upper_ << ") = '" << p.second << "'" << endl;
    return ss.str();
}

int main()
{
    Things things;
    things.insert( std::make_pair(Range(0.0, 5.0), "First") );
    things.insert( std::make_pair(Range(5.0, 10.0), "Second") );
    things.insert( std::make_pair(Range(10.0, 15.0), "Third") );

    transform( things.begin(), things.end(), ostream_iterator<string> (cout,""), dump );

    cout << "--------------------------------------" << endl;

    things[Range(1.5)] = "Revised First";

    transform( things.begin(), things.end(), ostream_iterator<string> (cout,""), dump );


    return 0;
}

... program output:

[0, 5) = 'First'
[5, 10) = 'Second'
[10, 15) = 'Third'
--------------------------------------
[0, 5) = 'Revised First'
[5, 10) = 'Second'
[10, 15) = 'Third'
John Dibling
Isn't this what I've posted?
Mykola Golubyev