3

lets say I have 2 maps:

map<int,vector<int>> id2courses;
map<int,vector <int>> id2allowed_courses;

And I would like for each key(id) see if list of courses contains only those courses that are allowed for that id. It can easily be done with a for loop, but I would like to exploit the fact that std::map is ordered, aka I would like to advance in both maps(incrementing the iterator with smaller key) and when I hit equal keys then I would like to do the comparisons. I know I can do it with nontrivial while loop, but I wonder is there a builtin STL way to do it

NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277

2 Answers2

2

Using std::set_intersection is a bit of a hack:

map<int,vector<int>> id2courses;
map<int,vector <int>> i2allowed_courses;

set_intersection(id2courses.begin(), id2courses.end(),
                 i2allowed_courses.begin(), i2allowed_courses.end(),
                 null_output_iterator(),
                 compare_and_do_something_if_same_key);

The null_output_iterator is from the question Discarding the output of a function that needs an output iterator.

compare_and_do_something_if_same_key will be passed a pair<const int, vector<int>> from each map. If the keys are equal you can do the processing you want. You also need to return a boolean to represent the ordering of elements:

bool compare_and_do_something_if_same_key(
    pair<const int, vector<int>& a, pair<const int, vector<int>& b)
{
    if(a.first == b.first) {
        doProcessing(a, b);
    }
    return a.first < b.first;
}

Caveat Emptor: The documentation says the compare function mustn't modify the objects being compared. I take that to mean mustn't modify in a way that would cause ordering problems. As you're not ordering by the second value in the pair I don't think this matters too much.

edit for readability:

This could be wrapped up into a named function:

template<typename Map, typename KeyValueProcessor> 
void process_values_for_matching_keys(
    Map& map1, Map& map2, KeyValueProcessor& keyValueProcessor);

And used as:

process_pairs_for_matching_keys(id2courses, i2allowed_courses, doProcessing);
Community
  • 1
  • 1
Peter Wood
  • 23,859
  • 5
  • 60
  • 99
  • Interestingly, using [`std::merge`](http://en.cppreference.com/w/cpp/algorithm/merge) instead of `set_intersection` produces the same results but is possibly a little less efficient as there are more assignments to the `null_output_iterator`. – Peter Wood Feb 14 '13 at 10:35
1

You may make use of set_intersection(), but this implementation, though easier to read will be not be as well performing. I would use a cycle and increment two iterators over the two maps. I don't think there is a faster solution. Even if there is something built-in it will perform at it best as good as this naive solution.

Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
  • Why wouldn't it perform well? – Peter Wood Feb 14 '13 at 09:21
  • set_intersection does one iteration over both containers. Next he will have to do another one to perform he wants on each of the elements to check for a given property. OP can do all that in a single iteration. – Ivaylo Strandjev Feb 14 '13 at 09:23
  • I was imagining hacking the comparison function to perform the action. See my answer – Peter Wood Feb 14 '13 at 09:30
  • @PeterWood I would challenge if that is more elegant than implementing two loops. Still it is helpful to know there is such option. – Ivaylo Strandjev Feb 14 '13 at 09:32
  • Set intersection need the values in the list to be sorted.and the Op wants the comparision of values when there is a match in the keys.So even if you use set intersection its not reducing the effort in traversing the maps. – Vijay Feb 14 '13 at 10:06
  • @sarathi it seems to me that not all keys are present in both maps so set_intersection will only leave the keys present in both maps. This will make the cycle much more elegant - two iterators that you increase on each iteration. Please note my answer still focuses on the fact that OP's best option is to do the cycles, not to use `set_intersection`. – Ivaylo Strandjev Feb 14 '13 at 10:08
  • but Op did not mention about the sort thing.if the list of values are not sorted,then you have to again sort before passing them to set_intersection.which will again take a lot of effort on cpu. – Vijay Feb 14 '13 at 10:11
  • 1
    @sarathi please note he has map. I suggest set_intersection for the keys of the map. `but I would like to exploit the fact that std::map is ordered, aka I would like to advance in both maps` – Ivaylo Strandjev Feb 14 '13 at 10:11