Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I access the elements in a c++ std::map by an integer index?

I have a map of elements that I would like to iterate through. Of course, the standard way to do that would be using a for loop with

for (map<string, int> iterator it = myMap.begin(); it != myMap.end(); ++it) {
    string thisKey = it->first;
    int thisValue = it->second;
}

but if I try and make this loop run parallel using OpenMP's parallel for construct, it doesn't work, and this is (apparently) a known issue, as it doesn't recognize this sort of loop construct.

So, my backup plan was to use an integer index iterator, and access the list of keys and values by index, as I would do in C# like so:

for (int i = 0; i < myMap.Count; ++i) {
    string thisKey = myMap.Keys[i];
    string thisValue = myMap.Values[i];
}

... yet I can't seem to find an equivalent method in C++. Is there a way to do this in C++ that I'm unaware of?

like image 456
Charles Avatar asked Aug 02 '11 21:08

Charles


People also ask

Can you access map with index C++?

Your map is not supposed to be accessed that way, it's indexed by keys not by positions. A map iterator is bidirectional, just like a list , so the function you are using is no more inefficient than accessing a list by position. If you want random access by position then use a vector or a deque .

How do I get map elements in C++?

C++ map find() function. C++ map find() function is used to find an element with the given key value k. If it finds the element then it returns an iterator pointing to the element. Otherwise, it returns an iterator pointing to the end of the map, i.e., map::end().

How do you view elements on a map?

C++ map access elementsValues are accessed by their keys via [] operator or at method. Accessing a key which does not exist throws an exception. We access two values from the stones map with [] and at .

How do you find the index of an element on a map?

There is no such thing as an index in a map. Maps are not stored (not necessarly, at least; and indeed they are not in most implementations) as a sequence of "pairs".


2 Answers

I don't know anything about OpenMP, so I don't know if it will optimize the following or not. But you could use std::advance, like so:

#include <map>
#include <string>
#include <iterator>
#include <iostream>

typedef std::map<std::string, int> Map;

int main() {
  Map m;
  m["one"] = 1;
  m["two"] = 2;
  for(int i = 0; i < m.size(); ++i) {
    Map::iterator it = m.begin();
    std::advance(it, i);
    std::string thiskey = it->first;
    int thisValue = it->second;
    std::cout << thiskey << "\n";
  }
}

But do be aware that std::advance is O(n), so your (single-threaded) complexity is O(n^2).


EDIT: If you copy the map elements to a vector, realize you can do that in one declaration:
std::vector<Map::value_type> v(m.begin(), m.end());

thus:

#include <map>
#include <string>
#include <iterator>
#include <iostream>
#include <vector>

typedef std::map<std::string, int> Map;

int main() {
  Map m;
  m["one"] = 1;
  m["two"] = 2;
  int i = 0;
  for( std::vector<Map::value_type> v(m.begin(), m.end());
    i < v.size(); ++i) {
    std::string thiskey = v[i].first;
    int thisValue = v[i].second;
    std::cout << thiskey << "\n";
  }
}
like image 57
Robᵩ Avatar answered Oct 04 '22 02:10

Robᵩ


Here are a few options that are relatively painless.

  1. Keep a std::vector or std::deque for array access, and a separate map of values. The leg work of ensuring that they are consistent is your problem.

  2. Use boost::multi_index to ensure consistency between the two index structures. As a word of warning, compile times are pretty long with this option. Consider using the pimpl idiom if you go this route.

I have no experience with OpenMP, so I cannot speculate if either of these options would be worthwhile in practice.

like image 25
Tom Kerr Avatar answered Oct 04 '22 04:10

Tom Kerr