I'd like to find out whether a given value is present in a map. Also getting the corresponding key(s) would be nice but is not required.
bool map::contains(string value);
Is there a simple way to do this other than to iterate over the whole map and comparing each value with the given value? Why is there no corresponding method in the STL?
std::map only indexes its elements by key; it does not index them by value. Therefore, there is no way to look up an element by its value without iterating over the map.
Take a look at Boost.Bimap:
Boost.Bimap is a bidirectional maps library for C++. With Boost.Bimap you can create associative containers in which both types can be used as key. A bimap<X,Y> can be thought of as a combination of a std::map<X,Y> and a std::map<Y,X>.
Using it is pretty straightforward, although you will of course need to consider the question of whether duplicate values are allowed.
Also, see Is there a Boost.Bimap alternative in c++11?
Related
I'm having a map<double, unique_ptr<Item>>. I would like to search this map, to find the item where a computed value is closest to the search value. The computed value can be generated by Item::compute which is a length computation, that I would like avoid doing for all elements. It can be assumed that this map is already ordered according to the results of the compute function.
So I thought that I could make a binary search, but the problem is, that I cannot really jump to the nth element in the map, since it is a map and not a vector. More specifically, I would need to get the middle item between two arbitrary items in the map. Is that possible? Is there a way an efficiant way to perform binary search within a map?
Use either the lower_bound() or the upper_bound() std::map methods. See the std::map documentation for both of these methods, that find an existing key nearest to the search key, if one does not exist. You don't need to code the binary search yourself, these methods do it for you.
Although using double as a map key is problematic, of course, I guess that using lower_bound() or upper_bound() might produce reasonable results, in this use case.
I'm having a hard time wrapping my head around unordered_maps and unordered_multimaps because my test code isn't producing what I've been told to expect.
std::unordered_map<string, int> names;
names.insert(std::make_pair("Peter", 4));
names.insert(std::make_pair("George", 4));
names.insert(std::make_pair("George", 4));
When I iterate through this list, I get one instance of George first, then Peter.
1) It's my understanding unordered_maps do not allow multiple keys to map to one value, and that multimaps due. Is this true?
2) Why can Peter and George coexist at a value of 4? What is happening to the second George? And for that matter, why is George appearing first when I iterate from begin() to end() if this is unordered?
3) What is the underlying representation of an unordered map vs. unordered multimap?
4) Is there a way to insert keys into either map without providing a value? E.g. have the compiler create its own hash function that I don't need to worry about when I retrieve keys and look for collisions?
I'll make it short:
No. Multi... refers to keys. A (non-multi)map can't have multiple equivalent keys with differeny values, ie. per key there is at most one value. A multi map can. The same holds for the unordered versions.
Peter != George, which is why they have different key and may very well have the same value.
A hashmap.
Use sets.
In your example the second insertion for George using a (non-multi) is skipped as the same key was previously inserted.
You want to use unordered_multimap to have several keys that are the same.
Since this is unordered you can't really hope to have any particular order, because it depends on the hash function.
If you want order in which you insert things, you need to use std::vector. Even normal maps, which are supposed to be ordered imply the comparison order, and not the order in which you insert things, for example string "AB" comes before "BB", because "A" is less than "B".
To insert without providing a value you need a set, and not a map.
The underlying structure of "unordered_" things is hashtable.
I'm implementing a multi-index map in C++11, which I want to be optimized for specific features. The problem I'm currently trying to solve, is to not store key elements more then once. But let me explain.
The problem arose from sorting histograms to overlay them in different combinations. The histograms had names, which could be split into tokens (properties).
Here are the features I want my property map to have:
Be able to loop over properties in any order;
Be able to return container with unique values for each property;
Accumulate properties' values in the order they arrive, but to be able to sort properties using a custom comparison operator after the map is filled;
I have a working implementation in C++11 using std::unordered_map with std::tuple as key_type. I'm accumulating property values as they arrive into a tuple of forward_lists. The intended use, is to iterate over the lists to compose keys.
The optimization I would like to introduce, is to only store properties' value in the lists, and not store them in tuples used as keys in the map. I'd like to maintain ability to have functions returning const references to lists of property values, instead of lists of some wrappers.
I know that boost::multi_index has similar functionality, but I don't need the overhead of sorting as the keys arrive. I'd like to have new property values stored sequentially, and only be sortable postfactum. I've also looked at boost::flyweight, but in the simplest approach, the lists will then be of flyweight<T> instead of T, and I'd like to not do that. (If that IS the best solution, I could definitely live with it.)
I know that lists are stable, i.e. once an element is created, its pointer and iterator remain valid, even after invoking list::sort(). Knowing that, can something be done to the map, to eliminate redundant copies of tuple elements? Could a custom map allocator help here?
Thanks for suggestions.
Have your map be from tuples of iterators to your prop containers.
Write a hash the dereferences the iterators and combines the result.
Replace the forward list prop containers with sets that first order on hash, then contents.
Do lookup by first finding in set, then doing lookup in hash.
If you need a different order for props, have another container of set iterators.
I am familiar with the standard libraries associative container map and the sequence container map. However I cant seem to understand the purpose of a set. While trying to understand std::set online I came across the following statement
A set is an STL container that stores values and permits easy lookup.
For example, you might have a set of strings:
std::set<std::string> S;
You can add a new element by writing
S.insert("foo";.
A set may not contain more than one element with the same key, so
insert won't add anything if S already contains the string "foo";
instead it just looks up the old element. The return value includes a
status code indicating whether or not the new element got inserted
So from the above text it seems to me like the set container only stores key and is not like a map which stores a key and a value. If this is true why is it an associative container and not a sequence container like a map ?
It is not really an associative container as it only stores values. It has the property of a mathematical set that if you put the same value in more than once you still only get one instance of that. This can be very useful. Suppose you were trying to get a list of all the words in a document; a set would be great as they would occur many times in the text but you would just get one of each word in the set.
You may think about it as an association of a key and a boolean value, telling whether the key is present in the set or not.
we have a collection of key and value pairs. We are in the need for a container which can help us to retrieve the value o(1) but also remember the insertion order so that when we do iteration, we could iterate like a inserting order. Since the key is a string, we will not able to use a set or similar structure.
Currently we have defined our own collection class which contains a list, also a map and the values are stored into 2 different structure.
Are there any readily available implementation available?
Sounds like you need a Boost Multi-Index container.