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.
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.
As it makes sense, lower_bound and upper_bound are absent for std::unordered_map because there is no order for elements.
However std::unordered_map has method equal_range. it return iterators for range corresponding to a key.
How does it make sense? Since there can be only one element with a key in std::unordered_map. It is just find method.
Also, in std::unordered_multimap, does it presence means all elements with same key will always come together while iterating unordered_multimap with a iterator?
How does it make sense?
It kind of does. The standard requires all associative container to offer equal_range so the non multi containers need to provide it. It does make writing generic code easier so I suspect that is the reason why all of the containers are required to use it.
Does it presence means all elements with same key will always come together while iterating unordered_map with a iterator?
Actually, yes. Since the all of the keys will have the same value they will hash to the same value which means they all get stored in the same bucket and will be grouped together since the keys compare equally. From [unord.req]/6
An unordered associative container supports unique keys if it may contain at most one element for each key. Otherwise, it supports equivalent keys. unordered_set and unordered_map support unique keys. unordered_multiset and unordered_multimap support equivalent keys. In containers that support equivalent keys, elements with equivalent keys are adjacent to each other in the iteration order of the container. Thus, although the absolute order of elements in an unordered container is not specified, its elements are grouped into equivalent-key groups such that all elements of each group have equivalent keys. Mutating operations on unordered containers shall preserve the relative order of elements within each equivalent-key group unless otherwise specified.
emphasis mine
It's for consistency with the other containers.
It makes more sense in the _multi variants, but is present in all the associative (and unordered associative) containers in the standard library.
It allows you to write code like
template <typename MapLike, typename KeyLike>
void do_stuff(const MapLike & map, const KeyLike & key)
{
auto range = map.equal_range(key);
for (auto it = range.first; it != range.second; ++it)
// blah
}
Which does not care about what specific container it is dealing with
cplusplus.com writes about std::unordered_map::equal_range:
Returns the bounds of a range that includes all the elements in the container with a key that compares equal to k. In unordered_map containers, where keys are unique, the range will include one element at most.
Also, in std::unordered_multimap, does it presence means all elements with same key will always come together while iterating unordered_multimap with a iterator?
In general, the order, in which elements stored in a std::unordered_multimap are obtained while traversing it, is actually not defined. However, note that std::unordered_multimaps are usually implemented as hash tables. By analysing such an implementation you will realize that the ordering is not going to be as "undefined" as someone might initially think.
At element insertion (or hash table rehashing), the value resulting of applying the hash function to an element's key is used to select the bucket where that element is going to be stored. Two elements with equal keys will result in the same hash value, therefore they will be stored in the same bucket, so they come togetherX while iterating an std::unordered_multimap.
XNote that even two elements with different keys might also result in the same hash value (i.e., a collision). However, std::unordered_multimap can handle these cases by comparing the keys against equality, and therefore still group elements with equal keys together.
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.
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);
Is there any C++ built-in set data structure which keeps the inserted order?
It doesn't a problem whether the set is a hash set or a set implemented by a balanced binary tree.
In C++11, both std::multiset and std::multimap are guaranteed to preserve the insertion order of same-valued/same-keyed elements.
Quoting from the C++11 standard,
23.2.4 Associative containers
4 An associative container supports unique keys if it may contain at most one element for each key. Otherwise,
it supports equivalent keys. The set and map classes support unique keys; the multiset and multimap classes
support equivalent keys. For multiset and multimap, insert, emplace, and erase preserve the relative
ordering of equivalent elements.
It must be explicitly stated that their unordered (hash) variants, std::unordered_multiset and std::unordered_multimap does not guarantee (it is unspecified) the relative order of insertion of elements.
I am not 100% sure if I understand what you are asking, but it sounds to me like a linked list would sufficiently suit your needs. You can just push and pop to keep the list in the order you placed it in. You can look here for a reference: http://www.cplusplus.com/reference/list/list/
Furthermore, you can use the unique method to remove duplicates making it emulate a set data structure.
Boost guarantees that all associative containers preserve insertion ordering.
a_eq.insert(t): If a range containing elements equivalent to t exists in a_eq, t is inserted at the end of that range.
ref: https://www.boost.org/doc/libs/1_68_0/doc/html/container/cpp_conformance.html#container.cpp_conformance.insertion_hints