Since there is no .resize() member function in C++ std::map I was wondering, how one can get a std::map with at most n elements.
The obvious solution is to create a loop from 0 to n and use the nth iterator as the first parameter for std::erase().
I was wondering if there is any solution that does not need the loop (at least not in my user code) and is more "the STL way to go".
You can use std::advance( iter, numberofsteps ) for that.
Universal solution for almost any container, such as std::list, std::map, boost::multi_index. You must check the size of your map only.
template<class It>
It myadvance(It it, size_t n) {
std::advance(it, n);
return it;
}
template<class Cont>
void resize_container(Cont & cont, size_t n) {
cont.erase(myadvance(cont.begin(), std::min(n, cont.size())),
cont.end());
}
The correct way for this is to use std::advance. But here is a funny (slow) way allowing to 'use resize on map'. More generally, this kind of trick can be used for other things working on vector but not on map.
map<K,V> m; //your map
vector< pair<K,V> > v(m.begin(), m.end());
v.resize(n);
m = map<K,V>(v.begin(),v.end());
Why would you want to resize a map?
The elements in a map aren't stored in any order - the first 'n' doesn't really mean anything
edit:
Interestingly std::map does have an order, not sure how useful this concept is.
Are the entries in the same sort order as the keys?
What does that mean? If you have Names keyed by SSN does that mean the names are stored in SSN numeric order?
A std::map is not a list. There are no "first n" elements.
BTW: Iterators become invalid if the container is changed.
If you really need a smaller map you could iterate though it and add all elements up to the n-th into a new map.
Related
I need suggestion to use STL containers in the best possible way to sort 3 sets of data
1. A ID (Integer)
2. First Value (String)
3. Second Value (String)
An example of the data structure is as below:
I want to use map as it is sorted at the time of insert and no need to execute a sorting algorithm separately. Since the ID can repeat it must be a multimap, and each data of a column is linked to each other so the rows will change in order to sort keeping the same values attached to a ID.
Sorting the ID and value is ok, but how do I sort 2 values as multimap can take only one value. From my thinking it will be multimap of a multimap or a struct of the data structure and then STL containers. But I want to make it as simple as possible. I need suggestion on how this can be achieved.
Thanks!
Having a map or a set makes sense if and only if you are going to do many insert/erase operations it. If the data structure is static, storing a vector and sorting it once is way more effective. That said, if I understand your question correctly, I think you don't need a map, but a multiset.
typedef pair<int, pair<string, string>> myDataType;
set<myDataType> mySet;
here, the operator < of pair will take care of the ordering.
If you don't want to refer to the id as elem.first, and to the strings as elem.second.first, and elem.second.second, then you can use a struct and overload operator < for it.
struct myType
{
int id;
string s1;
string s2;
};
bool operator < (const myType& t1, const myType& t2)
{
return make_tuple(t1.id, t1.s1, t1.s2) < make_tuple(t2.id, t2.s1, t2.s2);
}
You could just use a std::set<std::tuple<int, std::string, std::string>>. Tuples are lexicographically compared thus you would get the effect you want for free.
Live Demo
Elements in a multimap are sorted by the Key. You cannot 'sort' multimap. What you can do is to create vector of pairs<Key, Map<Key>::Interator> with elements fulfilling some logical condition and sort vector.
boost::hash has hashing functions for most builtin types including containers.
But as stated in the boost::hash_range function description, the hash algorithm for ranges
is sensitive to the order of the elements so it wouldn't be appropriate to use this with an unordered container
And thus there is no boost::hash specialization for std::unordered_map nor boost::unordered_map.
The question is:
Is there an "easy and efficient" way to hash an unordered_map without reimplementing a hash algorithm from scratch ?
The problem here is that there is no guarantee that the items even have an ordering among them.
So, sorting the items may very well not work for arbitrary unordered containers. You have 2 options:
Just XOR the hashes of all the individual elements. This is the fastest.
First sort the hashes of the containers, and then hash those. This may result in a better hash.
You can of course convert the unordered_map to some other data structure that has a guaranteed order and use that to generate the hash.
A better idea might be to hash each individual element of the map, put those hashes into a vector, then sort and combine the hashes. See for example How do I combine hash values in C++0x? to combine the hashes.
template<typename Hash, typename Iterator>
size_t order_independent_hash(Iterator begin, Iterator end, Hash hasher)
{
std::vector<size_t> hashes;
for (Iterator it = begin; it != end; ++it)
hashes.push_back(hasher(*it));
std::sort(hashes.begin(), hashes.end());
size_t result = 0;
for (auto it2 = hashes.begin(); it2 != hashes.end(); ++it2)
result ^= *it2 + 0x9e3779b9 + (result<<6) + (result>>2);
return result;
}
Testing this on shuffled vectors shows that it always returns the same hash.
Now to adapt that basic concept to work specifically with unordered_map. Since the iterator of unordered_map returns a pair, we need a hash function for that too.
namespace std
{
template<typename T1, typename T2>
struct hash<std::pair<T1,T2> >
{
typedef std::pair<T1,T2> argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& s) const
{
result_type const h1 ( std::hash<T1>()(s.first) );
result_type const h2 ( std::hash<T2>()(s.second) );
return h1 ^ (h2 + 0x9e3779b9 + (h1<<6) + (h1>>2));
}
};
template<typename Key, typename T>
struct hash<std::unordered_map<Key,T> >
{
typedef std::unordered_map<Key,T> argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& s) const
{
return order_independent_hash(s.begin(), s.end(), std::hash<std::pair<Key,T> >());
}
};
}
See it in action: http://ideone.com/WOLFbc
I think you may be confusing what hash is used for. It is for keys used to identify elements to determine where to store them. Two equivalent elements should has to the same value.
Are you trying to see if two unordered maps are equivalent and storing them in some kind of container?
The keys to an unordered map - well those are hashed. In fact the container would have been called hash_map except that such a container already existed.
But ok, suppose you really do want to store unordered-maps and compare to see if two are equivalent. Well you'd have to come up with a hashing algorithm that would return the same value regardless of the position of the elements it contains. A checksum of all its elements (keys and values) would be one possible way.
Note also that just because two elements have the same hash value, it doesn't mean they are equivalent. It just means that if the hash value differs they definitely are not equivalent. In fact checksums are often used to verify data for exactly this reason. A wrong checksum is proof the data is not valid, and given a good formula, a correct one makes it highly likely although not certain that it is.
I'm curious given that you are trying to hash the unordered_map to use it as a key, and given that once you've hashed the unordered_map you won't be changing it (unless you use it to create a new key), would the performance hit of converting the unordered_map to an ordered map be acceptable (and then, of course, hashing the ordered map and using that as a key)? Or is the problem with that approach that you need the faster lookup time provided by an unordered_map?
For what it's worth there may be a space advantage to using an ordered map (based on the accepted answer in the following post an unordered_map generally uses more memory):
Is there any advantage of using map over unordered_map in case of trivial keys?
You haven't specified any performance requirements, but if you just want a "quick and dirty" solution that won't require much coding on your behalf and would take advantage of boost::hash, you can copy the range of items from unordered_map to a vector, std::sort the vector, and then pass it to boost::hash_range.
Hardly the most effective solution, though, and not one you'd want to use often or with many elements.
My preferred approach would be a specialization of unordered_map that keeps a running, up-to-date hash of the contents — you shouldn't have to pass over all elements and perform a calculation to get the current value. Instead, a member of the data structure should reflect the hash, and be modified in real-time as elements are inserted or removed, and read when needed.
I have a method to which a vector's iterator is passed.
In this method I'd like to add some elements into the vector, but I am not sure whether this is possible when having only the iterator
void GUIComponentText::AddAttributes(vector<GUIComponentAttribute*>::iterator begin, vector<GUIComponentAttribute*>::iterator end)
{
for (vector<GUIComponentAttribute*>::iterator i = begin; i != end; ++i)
{
GUIComponentAttribute &attrib = *(*i);
// Here are the GUIComponentAttribute objects analyzed - if an object of a
// special kind appears, I would like to add some elements to the vector
}
}
Thanks
Markus
In the code you show, this is not possible. Especially because you should not add/remove elements to/from a vector while you iterate over it.
This is a long standing design "issue" in the STL. Iterators do not allow the modification of the structure of the underlying sequence they are iterating over: ie you can modify (sometimes) the elements themselves, but you cannot add/remove elements. Though InputIterator and OutputIterator are a bit special in this regard... hum...
This is actually the cause of the erase/remove idiom:
vec.erase(std::remove_if(vec.begin(), vec.end(), predicate), vec.end());
So, no, sorry, there is no way to actually modify the vector.
However, as exposed above, you can perfectly use the remove_if algorithm and simply return the new end of the valid range... or you can ask for the whole vector to begin with.
As noted by Björn, modifying a sequence structure while iterating over it is error-prone.
First, you'll have to change the interface. Given two iterators,
there's no way to get back to the container to which they refer; so if
you want to modify the container, you'll have to pass a reference to it,
i.e.:
void GUIComponentText::AddAttributes(
std::vector<GUIComponentAttribute*>& attributes )
{
for ( std::vector<GUIComponentAttribute*>::iter = attributes.begin();
iter != attributes.end();
++ iter )
{
// ...
}
}
Having done that: insertion can invalidate iterators. So it depends on
where you want to insert. If you want to insert at the current
position: std::vector<>::insert of a single element returns an
iterator to that element, which was inserted before your element, so you
can assign it to your iterator, adjust (if necessary), and continue:
iter = attributes.insert(iter, newAttribute);
++ iter; // Return to where we were...
If you're appending (push_back), the problem is a bit more complex;
you need to calculate the offset, then reconstruct the iterator:
size_t offset = iter - attributes.begin();
attributes.push_back( nweAttribute );
iter = attributes.begin() + offset;
In this case, it is probably simpler to iterate using a size_t and
[], rather than an iterator.
It is not possible to add elements into a vector whilst iterating over it. In addition, you most certainly cannot add one to a vector with just a pair of iterators- you'd need a pointer/reference to the whole vector object.
The best you could do is return a vector of new components to add by the the calling function.
If I have a structure like
std::map<string, int> myMap;
myMap["banana"] = 1;
myMap["apple"] = 1;
myMap["orange"] = 1;
How can I access myMap[0]?
I know that the map sorts internally and I'm fine with this, I want to get a value in the map by index. I've tried myMap[0] but I get the error:
Error 1 error C2679: binary '[' : no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion)
I realise I could do something like this:
string getKeyAtIndex (int index){
map<string, int>::const_iterator end = myMap.end();
int counter = 0;
for (map<string, int>::const_iterator it = myMap.begin(); it != end; ++it) {
counter++;
if (counter == index)
return it->first;
}
}
But surely this is hugely inefficient? Is there a better way?
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.
Your function could be written with help from std::advance(iter, index) starting from begin():
auto it = myMap.begin();
std::advance(it, index);
return it->first;
There may be an implementation specific (non-portable) method to achieve your goal, but not one that is portable.
In general, the std::map is implemented as a type of binary tree, usually sorted by key. The definition of the first element differs depending on the ordering. Also, in your definition, is element[0] the node at the top of the tree or the left-most leaf node?
Many binary trees are implemented as linked lists. Most linked lists cannot be directly accessed like an array, because to find element 5, you have to follow the links. This is by definition.
You can resolve your issue by using both a std::vector and a std::map:
Allocate the object from dynamic memory.
Store the pointer, along with the key, into the std::map.
Store the pointer in the std::vector at the position you want it
at.
The std::map will allow an efficient method to access the object by key.
The std::vector will allow an efficient method to access the object by index.
Storing pointers allows for only one instance of the object instead of having to maintain multiple copies.
Well, actually you can't. The way you found is very unefficient, it have a computational complexity of O(n) (n operations worst case, where n is the number of elements in a map).
Accessing an item in a vector or in an array have complexity O(1) by comparison (constant computational complexity, a single operation).
Consider that map is internally implemented as a red black tree (or avl tree, it depends on the implementation) and every insert, delete and lookup operation are O(log n) worst case (it requires logarithm in base 2 operations to find an element in the tree), that is quite good.
A way you can deal with is to use a custom class that have inside both a vector and a map.
Insertion at the end of the class will be averaged O(1), lookup by name will be O(log n), lookup by index will be O(1) but in this case, removal operation will be O(n).
Previous answer (see comment): How about just myMap.begin();
You could implement a random-access map by using a vector backing-store, which is essentially a vector of pairs. You of course lose all the benefits of the standard library map at that point.
you can use some other map like containers .
keep a size fields can make binary search tree easy to random access .
here is my implementation ...
std style , random access iterator ...
size balanced tree ...
https://github.com/mm304321141/zzz_lib/blob/master/sbtree.h
and B+tree ...
https://github.com/mm304321141/zzz_lib/blob/master/bpptree.h
std::map is an ordered container, but it's iterators don't support random access, but rather bidirectional access. Therefore, you can only access the nth element by navigating all its prior elements. A shorter alternative to your example is using the standard iterator library:
std::pair<const std::string, int> &nth_element = *std::next(myMap.begin(), N);
This has linear complexity, which is not ideal if you plan to frequently access this way in large maps.
An alternative is to use an ordered container that supports random access. For example, boost::container::flat_map provides a member function nth which allows you exactly what you are looking for.
std::map<string,int>::iterator it = mymap.begin() + index;
At the moment my solution is to iterate through the map to solve this.
I see there is a upper_bound method which can make this loop faster, but is there a quicker or more succinct way?
The end:
m.rbegin();
Maps (and sets) are sorted, so the first element is the smallest, and the last element is the largest. By default maps use std::less, but you can switch the comparer and this would of course change the position of the largest element. (For example, using std::greater would place it at begin().
Keep in mind rbegin returns an iterator. To get the actual key, use m.rbegin()->first. You might wrap it up into a function for clarity, though I'm not sure if it's worth it:
template <typename T>
inline const typename T::key_type& last_key(const T& pMap)
{
return pMap.rbegin()->first;
}
typedef std::map</* types */> map_type;
map_type myMap;
// populate
map_type::key_type k = last_key(myMap);
The entries in a std::map are sorted, so for a std::map m (assuming m.empty() is false), you can get the biggest key easily: (--m.end())->first
As std::map is assosiative array one can easily find biggest or smallest key very easily. By defualt compare function is less(<) operator so biggest key will be last element in map. Similarly if someone has different requirement anyone can modify compare function while declaring map.
std::map< key, Value, compare< key,Value > >
By default compare=std::less
Since you're not using unordered_map, your keys should be in order. Depending upon what you want to do with an iterator, you have two options:
If you want a forwards-iterator then you can use std::prev(myMap.end()). Note that --myMap.end() isn't guaranteed to work in all scenarios, so I'd usually avoid it.
If you want to iterate in reverse then use myMap.rbegin()
Since the map is just an AVL tree then, it's sorted -in an ascending order-. So, the element with largest key is the last element and you can obtain it using one of the following two methods:
1.
largestElement = (myMap.rbegin())-> first; // rbegin(): returns an iterator pointing to the last element
largestElement = (--myMap.end())->first; // end(): returns an iterator pointing to the theortical element following the last element