2

I have a requirement for a data structure which satisfies the following use cases:

  1. stores items by key
  2. functionality to retrieve the exact value by key
  3. functionality to retrieve the closest prior-value by key
  4. functionality to retrieve the closest subsequent-value by key

1 and 2 are obvious. For 3 (and 4), assuming the key is a custom Date object, the closest prior-value, on say a search for December 1, 2014, would return the value with the date closest to December 1, 2014. So if the prior values had keys of November 10, 11, 14, 15, and 29, then it would return November 29. For 4, the functionality is the same, however the closest date would be after December 1.

Currently I am using a std::map<Date, T>, but the requirements for 3 and 4 are new. Things I have considered:

  • keep using a std::map<Date, T> (log-n store and exact retrieve. closest match would be brute-force, so approximately n in terms of speed)
  • use a std::vector<T>, with my own sort routine (constant store, log-n retrieve for exact and closest; I can roll my own fetch routine and access members of the std::vector<T> by index for fast binary search)

I am leaning towards the std::vector<T>, since my T object has the Date built in (for the purposes of a std::map<Date, T> the Date is just a copy of the T.date() property).

The behaviour of these datastores is a mass-load up front, and occasional throughout the life of the object, but constant fetches on contents. So any data structure which is heavy on the front-end, but light on lookups, would work.

Thoughts?

tendim
  • 447
  • 3
  • 10
  • 1
    `std::lower_bound` + `std::upper_bound` or `std::map::lower_bound` + `std::map::upper_bound` – Filip Roséen - refp Feb 09 '15 at 11:18
  • Thanks; that is exactly what I needed. I had not heard of the `std::lower_bound` or `std::upper_bound` items before. Coincidentally, the description on cppreference.com is the same way I would have implemented my own roll-your-own version! – tendim Feb 09 '15 at 16:27
  • I'm too lazy to write it as an answer to your question, my recommendation is that you write it yourself (stackoverflow actually encourages self answered question (to serve as help for future visitors finding your question via search engines)) – Filip Roséen - refp Feb 09 '15 at 17:09
  • Sorry - not sure where I asked for someone to write it? – tendim Feb 10 '15 at 17:06
  • You didn't ask for it, though this is a *Q&A*-site.. – Filip Roséen - refp Feb 10 '15 at 18:23

2 Answers2

1

Elements in map are sorted. If your Date object has proper comparison operator (or your map got one) you can just use map::find to get your object iterator and then move that iterator forward and backward (cast to reverse_iterator) to get the closest value.

If the element is not present in container you should look at this: STL "closest" method?

Community
  • 1
  • 1
Maciej Oziębły
  • 1,769
  • 15
  • 14
  • Thanks for the tip; unfortunately that won't work as I am trying to find the closest items when the datastore does not have my object. – tendim Feb 09 '15 at 16:28
0

This is how I solved it:

#include <map>
#include <iostream>
#include <string>
#include <iterator> // for std::prev

using namespace std; // for brevity

void test(const map<int,string>& data, int key)
{
    cout << "searching for " << key << endl;

    auto range = data.equal_range(key);
    auto it1 = range.first;
    auto it2 = range.second;

    if (it1 != it2)
        cout << "\tfound: " << it1->second << endl;

    auto closestPrior = (it1 != data.begin()) ? prev(it1) : data.end();
    auto closestAfter = it2;

    if (closestPrior != data.end())
        cout << "\tprior: " << closestPrior->second << endl;
    if (closestAfter != data.end())
        cout << "\tafter: " << closestAfter->second << endl;
}

int main()
{
    map<int, string> data;
    data[1] = "one";
    data[5] = "five";
    data[9] = "nine";

    for (int i=0; i<11; ++i)
        test(data, i);
}

I use .equal_range() instead of calling both .lower_bound() and .upper_bound(). The only special handling is whether the lower bound is the begin iterator.

See it live.

DanielKO
  • 4,422
  • 19
  • 29