0
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?

expl0it3r
  • 325
  • 1
  • 7
  • 5
    `unordered_map` and order - not a good combination – Ted Lyngmo Aug 13 '20 at 15:51
  • I was under the impression that it would not touch the order of the elements at all - that it would keep the elements as was inserted within the sequence. – expl0it3r Aug 13 '20 at 15:52
  • How would I be able to order this with a standard map? – expl0it3r Aug 13 '20 at 15:53
  • std::map will sort them according to the default comparison operator, which would presumably be alphabetical on the first, then numeric on the second in case of a tie. – Kenny Ostrom Aug 13 '20 at 15:54
  • Ok, then you need to rethink. It'll be in "random" order. In what order do you want it? The order you put the elements in? In that case, you can't use an `undordered_map` or a `map` (that *will* order the elements in _key_ order). – Ted Lyngmo Aug 13 '20 at 15:54
  • std::unordered_map has no order because they are stored according to a hash function -- which is the entire point of the class to achieve O(1) lookup – Kenny Ostrom Aug 13 '20 at 15:54
  • @jasbindra00 what do you plan to use this map for? The example looks like a case of [stringly-typed programming](http://wiki.c2.com/?StringlyTyped). Do you actually need the values as strings? – shananton Aug 13 '20 at 15:57
  • "Not as expected" is just because you made up your expectations without the documentation. That shouldn't be confusing. – sweenish Aug 13 '20 at 15:58
  • @shananton I am reading from a file, whose data is written in the form {x,y} as a string. – expl0it3r Aug 13 '20 at 16:00
  • 1
    @jasbindra00 But why is the order of the map elements important to you? Are you planning on writing the map back out to a file afterwards, and want to preserve the same order as was read in? That is easy to accomplish using a separate `vector` of key values, or even a map of key-index pairs, to keep track of the order in the file, without ordering the map itself. – Remy Lebeau Aug 13 '20 at 16:02
  • 1
    Also, do you know the field names (`SIZEX` etc) in advance? If you do, consider parsing the file into a struct with the fields you expect instead of using a map of strings. – shananton Aug 13 '20 at 16:04

3 Answers3

3

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.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
1

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;
}
Kenny Ostrom
  • 5,639
  • 2
  • 21
  • 30
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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • How could I design a predicate for the std::map such that the elements are maintained in that input sequence? – expl0it3r Aug 13 '20 at 15:54
  • 1
    Note that `std::map` won't work either, unless you can come up with a comparator that will generate the desired order. – François Andrieux Aug 13 '20 at 15:54
  • 2
    @jasbindra00 If you need to maintain a specific sequence a vector or list is probably better. – Lukas-T Aug 13 '20 at 15:55
  • @jasbindra00 If the keys you want to add to a `std::map` are fixed, you could easily create a comparator that returns the desired order, for example by storing the key names in an array and using the indexes for ordering. But, if the keys are not fixed, then `std::map` is probably not the right container for you. Why is the order of the map elements important to you? – Remy Lebeau Aug 13 '20 at 16:00
  • @RemyLebeau The order is important to me since I had planned to get all the values from each key from within the map, and insert them into a stringstream object, whereby I could really quickly and 'elegantly' initialise an object with that stream using the >> operator. Eg stream>>x1>>x2>>x3. – expl0it3r Aug 13 '20 at 16:03
  • 1
    These anonymous downvotes baffles me sometimes ... How is this not answering the question? – Ted Lyngmo Aug 13 '20 at 16:04
  • 1
    @jasbindra00 If the only way you plan to access your elements is by iteration, then a map is not desirable. A map is desirable when you will want to search for values by key in an unpredictable order. – François Andrieux Aug 13 '20 at 16:05
  • 3
    @jasbindra00 that doesn't really explain WHY the order of the map elements is important. You can easily iterate a map from front to end in whatever order the map chooses to use, and look up specific values by key values. Why do you want a *particular order* of the keys? Please edit your question to provide an example of an actual issue you are trying to solve. – Remy Lebeau Aug 13 '20 at 16:05