std::unordered_map not behaving as expected - c++

std::unordered_map<std::string,std::string> mymap;
mymap.insert(std::make_pair("ELEMENTTYPE", "NEWINTERFACE"));
mymap.insert(std::make_pair("STYLEFILE", "Style_Light.txt"));
mymap.insert(std::make_pair("ELEMENTNAME", "IN1"));
mymap.insert(std::make_pair("POSITIONX", "0"));
mymap.insert(std::make_pair("POSITIONY", "0"));
mymap.insert(std::make_pair("SIZEX", "50"));
mymap.insert(std::make_pair("SIZEY", "50"));
I expected the map to have those elements in that order, but instead, it is :
-SIZEY
-ELEMENTTYPE
-STYLEFILE
-SIZEX
-POSITIONX
-POSITIONY
I am very confused; why is the std::unordered_map ordering my elements?

The term unordered in std::unordered_map means that the order is unspecified. You cannot rely on the order of an unordered_* container. All associative containers (containers which map a value to a key) will mess with the order of the elements because this order allows them to achieve better performance when searching by key, which is usually the goal of using a map.
If you want to control the order yourself, you can use std::vector<std::pair<std::string, std::string>>. You'll have a set of pairs, ordered the way you want, but you forfeit the fast find implementations associative containers provide.

You want a specific arbitrary order
std::unordered_map has no particular order that you can control
std::map sorts the keys according to a function
If you want something like python's OrderedDict in c++ here are some duplicate answers:
C++ dictionary/map with added order
A std::map that keep track of the order of insertion?
Perhaps you are trying to be too fancy, when all you really need is a basic struct object. It's just a variable and its members are just variables that you get when and how you want.
#include <vector>
#include <string>
enum elementtype_enum { NEWINTERFACE, OTHER };
struct my_element_type {
std::string name;
elementtype_enum type;
std::string style_file;
int positionx, positiony, sizex, sizey;
};
int main() {
std::vector<my_element_type> elements;
my_element_type e { "IN1", NEWINTERFACE, "Style_Light.txt", 0, 0, 50, 50 };
elements.push_back(e);
return 0;
}

By its very name, a std::unordered_map is unordered. The order of its elements is unspecified, and will be dependent on the hash of the Key values.
If the order of the elements is important to you, use std::map instead. By default, it uses the Key's operator< for ordering, but you can optionally provide a custom Compare type if you want to order the elements yourself.

Related

Sorting both ID and 2 sets of values using STL containers

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.

Is there a way to prevent insert or erase on STL unordered_map?

I frequently use unordered_maps with fixed / constant keys, but mutable values. Example: If you have an enum Dimension{ X, Y }, you might want to store a data point for each but never allow inserts or deletes for the map. Updates are OK.
Example initialisation:
typedef std::unordered_map<Dimension, std::size_t> Dimension_To_Size_Map;
// assume std::hash has template specialisation for enum
Dimension_To_Size_Map dimension_To_Size_Map =
{ { Dimension.X, 0 }, { Dimension.Y, 0 } };
dimension_To_Size_Map[Dimension.X] = 12; // update is ok
dimension_To_Size_Map[Dimension.Y] = 17; // update is ok
dimension_To_Size_Map[(Dimension)7] = 22; // insert not allowed
dimension_To_Size_Map.erase(Dimension.X); // erase not allowed
It is possible to prevent insert or erase, but allow update, on STL unordered_map?
One idea: Copy, rename, and modify an existing implementation of unordered_map to remove insert and erase.
You could derive your own map class from std::map via private inheritance and expose only the functions of std::map that you want to provide access to.
Take a sorted std::vector of pair<const K, V>s. Write manual [] and find and begin and the few methods you care about.
map is slow, and one of the reasons it is slow is that it allows new elements. If you don't allow new elements, write a ridiculously faster container.

In a C++ map, is there any way to search for the key given a value?

In a C++ std::map, is there any way to search for the key given the mapped value? Example:
I have this map:
map<int,string> myMap;
myMap[0] = "foo";
Is there any way that I can find the corresponding int, given the value "foo"?
cout << myMap.some_function("foo") <<endl;
Output: 0
std::map doesn't provide a (fast) way to find the key of a given value.
What you want is often called a "bijective map", or short "bimap". Boost has such a data structure. This is typically implemented by using two index trees "glued" together (where std::map has only one for the keys). Boost also provides the more general multi index with similar use cases.
If you don't want to use Boost, if storage is not a big problem, and if you can affort the extra code effort, you can simply use two maps and glue them together manually:
std::map<int, string> myMapForward;
std::map<string, int> myMapBackward; // maybe even std::set
// insertion becomes:
myMapForward.insert(std::make_pair(0, "foo"));
myMapBackward.insert(std::make_pair("foo", 0));
// forward lookup becomes:
myMapForwar[0];
// backward lookup becomes:
myMapBackward["foo"];
Of course you can wrap those two maps in a class and provide some useful interface, but this might be a bit overkill, and using two maps with the same content is not an optional solution anyways. As commented below, exception safety is also a problem of this solution. But in many applications it's already enough to simply add another reverse map.
Please note that since std::map stores unique keys, this approach will support backward lookup only for unique values, as collisions in the value space of the forward map correspond to collisions in the key space of the backward map.
No, not directly.
One option is to examine each value in the map until you find what you are looking for. This, obviously, will be O(n).
In order to do this you could just write a for() loop, or you could use std::find_if(). In order to use find_if(), you'll need to create a predicate. In C++11, this might be a lambda:
typedef std::map <unsigned, Student> MyMap;
MyMap myMap;
// ...
const string targetName = "Jones";
find_if (myMap.begin(), myMap.end(), [&targetName] (const MyMap::value_type& test)
{
if (test.second.mName == targetName)
return true;
});
If you're using C++03, then this could be a functor:
struct MatchName
: public std::unary_function <bool, MyMap::value_type>
{
MatchName (const std::string& target) : mTarget (target) {}
bool operator() (const MyMap::value_type& test) const
{
if (test.second.mName == mTarget)
return true;
return false;
}
private:
const std::string mTarget;
};
// ...
find_if (myMap.begin(), myMap.end(), MatchName (target));
Another option is to build an index. The index would likely be another map, where the key is whatever values you want to find and the value is some kind of index back to the main map.
Suppose your main map contains Student objects which consist of a name and some other stuff, and the key in this map is the Student ID, an integer. If you want to find the student with a particular last name, you could build an indexing map where the key is a last name (probably want to use multimap here), and the value is the student ID. You can then index back in to the main map to get the remainder of the Student's attributes.
There are challenges with the second approach. You must keep the main map and the index (or indicies) synchronized when you add or remove elements. You must make sure the index you choose as the value in the index is not something that may change, like a pointer. If you are multithreading, then you have to give a think to how both the map and index will be protected without introducing deadlocks or race conditions.
The only way to accomplish this that I can think of is to iterate through it. This is most likely not what you want, but it's the best shot I can think of. Good luck!
No, You can not do this. You simply have to iterate over map and match each value with the item to be matched and return the corresponding key and it will cost you high time complexity equal to O(n).
You can achieve this by iterating which will take O(n) time. Or you can store the reverse map which will take O(n) space.
By iterating:
std::map<int, string> fmap;
for (std::map<int,string>::iterator it=fmap.begin(); it!=fmap.end(); ++it)
if (strcmp(it->second,"foo"))
break;
By storing reverse map:
std::map<int, string> fmap;
std::map<string, int> bmap;
fmap.insert(std::make_pair(0, "foo"));
bmap.insert(std::make_pair("foo", 0));
fmap[0]; // original map lookup
bmap["foo"]; //reverse map lookup

std::map rotate method or algorithm using stl::map

iam developing a class that inside holds an std::map, by now the funcionality was optimal, but now i have a requirement to rotate the map, i mean by rotate change order in wich the map elements id besides the values corresponding to those values , by example:
Given:
Map[122]=1
Map[12]=2
Map[3]=45
applyng the rotation algorithm once:
Map[12]=2
Map[3]=45
Map[122]=1
applyng the rotation algorithm again:
Well, my first intention is write a algoritm that perform this operation, but i new in c++
Map[3]=45
Map[122]=1
Map[12]=2
Do i have a proper solution in stl libs that i cannot see by now¡?
thx
No.
The order of map elements is not something you control. It's inherent, based on sort key.
Sure, you can provide your own comparator in order to manipulate the underlying order of the container.
However, you should not be relying on order in a map. It is not a sequence container, and is simply not designed for you to use order as a property.
Instead of this "rotating", why not begin your iteration at a different place in the container each time, and "wrap-around"?
I think you might be confusing "mapping" with "storage". In a mathematical (or algorithmic) sense, if you "map" a key to a value, then that is a one to one mapping and until it has been changed, when you look up that key, you will always get that value. It doesn't matter yet how it actually works or whether whatever object is used to implement the map has been "rotated" or not. Look up a key, get the value. In your case, before or after rotation, if you look up "12" for example, you will always get 2. Do you see what I'm saying? Order here, doesn't matter. Therefore, if you use std::map from the STL, you lose control over guarantees on the order in which the elements are stored.
Now, what you're asking has to do with the implementation and in particular, with how the elements are stored, so what you need is an STL container that guarantees order. One such container is a vector. It seems to me that what you might want is probably a vector of pairs. Something like this would work:
#include <vector>
#include <map> //for std::pair
#include <iostream>
#include <algorithm> //for std::rotate
typedef std::pair<int,int> entry;
typedef std::vector<entry> storage;
void print( const char* msg, const storage& obj )
{
std::cout<<msg<<std::endl;
for(auto i : obj)
{
std::cout << i.first << "," << i.second << std::endl;
}
}
void lookup(int key, const storage& obj)
{
for(auto i : obj)
{
if( i.first == key )
{
std::cout<<"\t"<<key<<"=>"<<i.second<<std::endl;
return;
}
}
std::cout<<key<<"not found"<<std::endl;
}
int main()
{
storage mymap = {entry(122,1),entry(12,2),entry(3,45)};
print("Before rotation", mymap);
lookup(12,mymap);
std::rotate(mymap.begin(),mymap.begin()+1,mymap.end());
print("After one rotation", mymap);
lookup(12,mymap);
std::rotate(mymap.begin(),mymap.begin()+1,mymap.end());
print("After one more rotation", mymap);
lookup(12,mymap);
return 0;
}
Note, however, that because you're using a vector, it will not protect you from adding duplicate pairs or pairs with different keys but the same value and vice versa. If you want to maintain a one to one mapping, you will have to make sure that when you insert elements in, that the "key" and the "value" are not repeated anywhere else in the vector. That should be pretty easy for you to figure out after some reading on how std::vector works.
To extend Lightness's answer, which I believe is the correct one. If you wan't more control over your map you should use a static matrix instead.
Matrices provide many more rotational options using simple math, instead of the cyclical rotation you're trying to implement.

Does the C++ standard library have a set ordered by insertion order?

Does the C++ standard library have an "ordered set" datastructure? By ordered set, I mean something that is exactly the same as the ordinary std::set but that remembers the order in which you added the items to it.
If not, what is the best way to simulate one? I know you could do something like have a set of pairs with each pair storing the number it was added in and the actual value, but I dont want to jump through hoops if there is a simpler solution.
No single, homogeneous data structure will have this property, since it is either sequential (i.e. elements are arranged in insertion order) or associative (elements are arranged in some order depending on value).
The best, clean approach would perhaps be something like Boost.MultiIndex, which allows you to add multiple indexes, or "views", on a container, so you can have a sequential and an ordered index.
Instead of making a std::set of whatever type you're using, why not pass it a std::pair of the object and an index that gets incremented at each insertion?
No, it does not.
Such a container presumably would need two different iterators, one to iterate in the order defined by the order of adding, and another to iterate in the usual set order. There's nothing of that kind in the standard libraries.
One option to simulate it is to have a set of some type that contains an intrusive linked list node in addition to the actual data you care about. After adding an element to the set, append it to the linked list. Before removing an element from the set, remove it from the linked list. This is guaranteed to be OK, since pointers to set elements aren't invalidated by any operation other than removing that element.
I thought the answer is fairly simple, combine set with another iteratable structure (say, queue). If you like to iterate the set in the order that the element been inserted, push the elements in queue first, do your work on the front element, then pop out, put into set.
[Disclaimer: I have given a similar answer to this question already]
If you can use Boost, a very straightforward solution is to use the header-only library Boost.Bimap (bidirectional maps).
Consider the following sample program that will display some dummy entries in insertion order (try out here):
#include <iostream>
#include <string>
#include <type_traits>
#include <boost/bimap.hpp>
using namespace std::string_literals;
template <typename T>
void insertByOrder(boost::bimap<T, size_t>& mymap, const T& element) {
using pos = typename std::remove_reference<decltype(mymap)>::type::value_type;
// We use size() as index, therefore indexing the elements with 0, 1, ...
mymap.insert(pos(element, mymap.size()));
}
int main() {
boost::bimap<std::string, size_t> mymap;
insertByOrder(mymap, "stack"s);
insertByOrder(mymap, "overflow"s);
// Iterate over right map view (integers) in sorted order
for (const auto& rit : mymap.right) {
std::cout << rit.first << " -> " << rit.second << std::endl;
}
}
The funky type alias in insertByOrder() is needed to insert elements into a boost::bimap in the following line (see referenced documentation).
Yes, it's called a vector or list (or array). Just appends to the vector to add element to the set.