0

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

Ricardo_arg
  • 520
  • 11
  • 28

3 Answers3

4

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

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

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.

Carl
  • 43,122
  • 10
  • 80
  • 104
0

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.

gifnoc-gkp
  • 1,506
  • 1
  • 8
  • 17