Is there any container available in C++ STL to store unsorted key value pair with duplicate keys?
I was thinking std::unordered_multimap container will help me in this case but the elements with equivalent keys are grouped together in this.
I would recommend you to look at sequence containers. Basically you can store std::pair< key, value > at some sequence container.
If you just need to store key-value pairs and sometimes add new key-value pair at the end of the container then std::vector is enough. If you additionally want to insert elements in the beginning of the container then look at std::deque. And so on...
So the best strategy is to analyze your constraints and choose the appropriate sequence container.
Related
When iterating over an unordered map of values, std::unordered_map<Foo, Bar>, it will use an iterator pointing to values instd::pair<Foo, Bar>. This makes it seem like std::unordered_map stores its values internally as std::pairs of values.
If I'm not mistaken, std::unordered_map works by hashing the key and using that for lookups. So, if the internal structure is something like a list of pairs, how does it know which pair has the hashed key? Wouldn't it need to hash the whole pair, value included?
If the internal structure does not hold pairs, does calling std::unordered_map::begin() then create a std::pair object using the data in the map? Then how does modifying the data in the pair also modify the data in the actual map itself?
Thank you.
Let's pretend that the map is really a single vector:
std::vector<std::pair<Foo, Bar>> container;
It's easy to visualize that iterating over this container iterates over std::pairs of two classes.
The real unordered map works the same way, except instead of a vector the map stores std::pair<Foo, Bar>s in a hash table, with additional pointers that stitch the whole hash table together, that are not exposed via the map's iterators.
The way that associative containers, like maps, get loosely explained and described -- as a key/value lookup -- makes it sound like in the maps keys and values are stored separately: here's a hash table of keys, and each key points to its corresponding value. However that is not the case. The key and its value are kept together, tightly coupled in discrete std::pair objects, and the map's internal structure arranges them in a hashed table that the iterator knows how to iterate over.
So, if the internal structure is something like a list of pairs, how does it know which pair has the hashed key?
Neither. An unordered map can be loosely described as a:
std::vector<std::list<std::pair<Key, Value>>>
A key's hash is the index in the vector. All Keys in the ith position in this vector have the same hash value. All keys with the same hash are stored in a single linked list.
I inserted the elements to the unordered_map with this code:
myMap.insert(std::make_pair("A", 10));
myMap.insert(std::make_pair("B", 11));
myMap.insert(std::make_pair("C", 12));
myMap.insert(std::make_pair("D", 13));
But when I used this command to print the keys
for (const auto i : myMap)
{
cout << i.first << std::endl;
}
they are not in the same order as I inserted them.
Is it possible to keep the order?
No, it is not possible.
Usage of std::unordered_map doesn't give you any guarantee on element order.
If you want to keep elements sorted by map keys (as seems from your example) you should use std::map.
If you need to keep list of ordered pairs you can use std::vector<std::pair<std::string,int>>.
Not with an unordered associative data structure. However, other data structures preserve order, such as std::map which keeps the data sorted by their keys. If you search Stackoverflow a little, you will find many solutions for a data structure with fast key-based lookup and ordered access, e.g. using boost::multi_index.
If it is just about adding values to a container, and taking them out in the order of insertion, then you can go with something that models a queue, e.g. std::dequeue. Just push_back to add a new value, and pop_front to remove the oldest value. If there is no need to remove the values from the container then just go with a std::vector.
Remarkably common request without too many clean,simple solutions. But here they are:
The big library: https://www.boost.org/doc/libs/1_71_0/libs/multi_index/doc/tutorial/index.html Use unique index std::string (or is it char?) and sequenced index to retain the order.
Write it yourself using 2 STL containers: Use a combination of std::unordered_map (or std::map if you want sorted key order traverse as well) and a vector to retain the sequenced order. There are several ways to set this up, depending on the types on your keys/values. Usually keys in the map and the values in the vector. then the map is map<"key_type",int> where the int points to the element in the vector and therefore the value.
I might have a play with a simple template for a wrapper to tie the 2 STL containers together and post it here later...
I have put a proof of concept up for review here:
I went with std::list to store the order in the end, because I wanted efficient delete. But You might choose std::vector if you wanted random access by insertion order.
I used a a list of Pair pointers to avoid duplicate key storage.
I have a multimap containing over 5 million pairs and I need to swap the keys with the values.
unordered_multimap<int, int> edge;
Due to the large size of the container and the processes involved, I would prefer to not have to create a new multimap with the swapped pairs by iterating over each element of the map.
What would be the best way, if any, to do this in place?
The proper approach is not to do this at all, but instead to have a bi-directional map in the first place, on which you can perform lookup in either direction.
Consider looking into Boost.Bimap.
You can not do this in-place.
The map you have stored the elements based of the hash values of its key. If you want to hash on a different key (the former value) you have to rebuild the whole map or think of a different way to store the elements.
Boost.Bimap (as suggested by Lightness Races in Orbit) for example supports bidirectional unordered multimaps.
I want to use a std::multimap container, but I need to know that it will always maintain order, as in the first element in will be the first element iterated over and the second will always be the second.
What I'm asking is this:
Is std::multimap< key, value > equivalent to std::vector< std::pair< const key, std::vector< value > > >
A multimap is not the equivalent of a vector, not in terms of implementation. Multimaps are usually implemented as a binary search tree. The elements of a multimap are always kept in a sorted order by their key following a strict weak order criteria indicated by the comparison object.
Thus, when you iterate over the elements of a multimap their order is the sorted order provided by the comparison object.
Is std::multimap< key, value > equivalent to std::vector< std::pair<
const key, std::vector< value > > > ?
No, these are two different containers and they exhibit many differences in how they store underlying data, how they manage the memory, how you can access this data and in order the data is stored. In vector the data is stored in order that you have push_back ed it, but in multimap data is always sorted, so e.g. the last value you have inserted into multimap may be actually accessed with multimap.begin() or multimap.begin() + 10.
You can have an integer key in multimap and insert with incremented key to force order of sort be same as order of insertion.
Although they are not the same in terms of implementation, your question indicates that you're really just concerned about the ordering. I found the following information related to the ordering:
Multimaps are associative containers that store elements formed by a
combination of a key value and a mapped value, following a specific
order, and where multiple elements can have equivalent keys.
Internally, the elements in a multimap are always sorted by its key
following a specific strict weak ordering criterion indicated by its
internal comparison object (of type Compare).
Source, cplusplus.com
A std::vector< std::pair< const key, std::vector< value > > > allows you to have any ordering of the key elements, whereas a std::multimap<key, value> doesn't.
From cppreference:
Multimap is an associative container that contains a sorted list of key-value pairs, while permitting multiple entries with the same key. Sorting is done according to the comparison function Compare, applied to the keys.
It sounds like you are asking what is the order among equivalent entries.
The order of the key-value pairs whose keys compare equivalent is the order of insertion and does not change. (since C++11)
You can keep a vector in the same order as what a multimap provides, by making sure that you insert new entries after all the existing equivalent entries, but before any entries who's keys are later in the order. A simple way would to gate all insertion through
vec.insert(std::upper_bound(vec.begin(), vec.end(), to_insert, key_compare), to_insert);
Since maps dont allow duplicate values . Are there any other containers that are part of C++ standard library that allow duplicates that store values by key value pair?
You can use std::multimap
Multimap is a Sorted Associative Container that associates objects of type Key with objects of type Data. multimap is a Pair Associative Container, meaning that its value type is pair. It is also a Multiple Associative Container, meaning that there is no limit on the number of elements with the same key.