开发者

Access map value via index?

I have this map:

m.insert(pair<int, string>(10, "map1"));
m.insert(pair<int, string>(11, "map2"));
m.insert(pair<int, string>(12, "map3"));
m.insert(pair<int, string>(13, "map4"开发者_运维技巧;));
m.insert(pair<int, string>(14, "map5"));

Then, I let user enter a number:

Please select:
1. Map1
2. Map2
3. Map3
4. Map4
5. Map5

Lets say, if user enters 3, how do I get the value: 12??


With the current setup you have, there's no easy way to do this; you'd have to iterate over all the elements of the map looking for the one that had Map3 as a value.

The map is optimized for looking up relationships in one direction. Given a map<K, V>, you can easily map from Ks to Vs, but not the other way around. The reason is that because you can store any V as a value, there's no guarantee that you'll get a unique inverse. That is, given this map:

 0 -> 0
 1 -> 0 
 2 -> 1

There's no meaningful way to say which key has value 0; there are two such keys, 0 and 1.

You have many options here. First, you could turn the map around and instead associate strings with integers, rather than integers with strings. Based on your use case, this seems like what you wanted to do in the first place. If you did that, then you could just use the square brackets operator to look up the associated value:

cout << m["Map3"] << endl;

Or, if you were concerned about what would happen with missing values, then you could write

map<string, int>::iterator itr = m.find("Map3");
if (itr != m.end()) {
    /* ... use itr to read the values ... */
}

Alternatively, if you really do have to have the map from integers to strings, and you know that each integer is paired with a unique string and vice-versa (that is, the map is a bijection), then you could use a Boost.Bimap to encode this bidirectional relationship. This would make it very easy to go back and forth between keys and values.

Hope this helps!


std::map does not track the order in which its elements are inserted; the elements are stored in sorted order instead of insertion order. If you need to keep track of the order in which elements were inserted, you need to do so yourself. One way to do this would be to keep a second container that stores the keys in order, using a std::vector, for example:

std::vector<int> insertion_order;

m.insert(std::make_pair(10, "map1"));
insertion_order.push_back(10);

Then, the key of the Nth inserted element is at index N - 1 in the insertion_order sequence.


Map the integers in the menu to the data you wish to store. Consider:

struct data {
    data(int n, const std::string& s) : s(s), n(n) { }
    std::string s;
    int n;
};

// ...
std::map<int,data> m;
m.insert(make_pair(1, data(10, "Map1"));
m.insert(make_pair(2, data(11, "Map2"));
m.insert(make_pair(3, data(12, "Map3"));

int n = m[3].n;  // 12


From the docs:

Compare: Comparison class: A class that takes two arguments of the key type and returns a bool. The expression comp(a,b), where comp is an object of this comparison class and a and b are key values, shall return true if a is to be placed at an earlier position than b in a strict weak ordering operation. This can either be a class implementing a function call operator or a pointer to a function (see constructor for an example). This defaults to less<Key>, which returns the same as applying the less-than operator (a<b). The map object uses this expression to determine the position of the elements in the container. All elements in a map container are ordered following this rule at all times.

So the map class doesn't maintain the order of its elements as an array would. If there were an indexing operator, it would like not return the i'th element added to the map. It is an assocoiative collection, and you don't typically use that type of data structure when you need to maintain order by virtue of time of insertion.


With newer versions of C++ (since C++17), we have the std::advance() function which can be used like so:

auto it = m.begin();
std::advance(it, index);
return it->first;   // or it->second depending on what you need

This is not a standard use case for an std::map so expect the std::advance() to become slower as the map grows larger and larger (i.e. complexity is linear or O(n) in this situation).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜