Thread: Is it possible to swap the key values and the mapped values around in a map?

  1. #31
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Programmer_P View Post
    One line of code versus several lines of code is definitely the way to go, IMO...
    This is why I said write a function. Then it is only one line of code.

    Code:
    map<string, int> data; //the map
    string name = getstringfromint(data, 16); // example call
    Considering the maps are const, you should keep the method you are using. Unfortunately in C++ you can't make use of void*, or otherwise dynamically type the value in a map, or what I would do would be to add a value to the original map with a unique string key like "myprog_index_map" with the value pointing to the second map. This makes keeping the relationship between them simple.

    But you can't do that, you might want to make this map into a class which contains both of them, then you can manipulate a single object with both maps in it.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  2. #32
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by MK27 View Post
    This is why I said write a function. Then it is only one line of code.
    What?!
    It is already one line of code:

    Code:
    multimap<unsigned int, string> swappedMap = swap(enumerationsMap);
    Code:
    map<string, int> data; //the map
    string name = getstringfromint(data, 16); // example call
    You're doing something different there, obviously...
    Creating a map with strings as key values, and ints as mapped values, then calling a "getstringfromint" funtion? Btw, that's 2 lines...
    Considering the maps are const, you should keep the method you are using. Unfortunately in C++ you can't make use of void*, or otherwise dynamically type the value in a map, or what I would do would be to add a value to the original map with a unique string key like "myprog_index_map" with the value pointing to the second map. This makes keeping the relationship between them simple.
    Not sure if I'm getting you there...
    What would be the point of adding such a value to the original map?
    And how would you point it at the second map?
    But you can't do that, you might want to make this map into a class which contains both of them, then you can manipulate a single object with both maps in it.
    I already have a class which contains the original map. You then call classObject.getEnumerationsMap() to get a copy of that map. Like I was saying earlier, I could easily create the second map as a member of the same class, and then add another function for retrieving that map, but I wrote the swap function so I can swap any map around, in case I need such a thing later on, I will have already written it.
    The purpose of the swap function is to be able to easily swap the key values and the mapped values around in any kind of map passed to the function, and it will then return a multimap containing all that stuff. That can be accomplished in one line of code like I just demonstrated.
    I'm an alien from another world. Planet Earth is only my vacation home, and I'm not liking it.

  3. #33
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by MK27 View Post
    Considering the maps are const, you should keep the method you are using. Unfortunately in C++ you can't make use of void*, or otherwise dynamically type the value in a map, or what I would do would be to add a value to the original map with a unique string key like "myprog_index_map" with the value pointing to the second map. This makes keeping the relationship between them simple.

    But you can't do that, you might want to make this map into a class which contains both of them, then you can manipulate a single object with both maps in it.
    The types are static, aren't they? Then of course you can make a pointer to such a map, if you wanted. If I understand you correctly.
    Programmer_P: There is a thing called the edit button. Use it. Posting thrice is a row is considered bad on many forums.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #34
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by Elysia View Post
    The types are static, aren't they? Then of course you can make a pointer to such a map, if you wanted. If I understand you correctly.
    I don't know who you directed that question at, but I'll assume its me:
    Why would I want to make the maps static (and no, the maps are not currently static)? What advantage would the 'static' keyword give me in this case?
    Programmer_P: There is a thing called the edit button. Use it. Posting thrice is a row is considered bad on many forums.
    True. I hate editing though.
    It makes me look stupid, because it looks like I didn't complete the thought the first time around (and I did, I just had a new thought, hence the new post).
    haha.
    I'm an alien from another world. Planet Earth is only my vacation home, and I'm not liking it.

  5. #35
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Programmer_P View Post
    I don't know who you directed that question at, but I'll assume its me:
    Why would I want to make the maps static (and no, the maps are not currently static)? What advantage would the 'static' keyword give me in this case?
    It was directed at MK27, not you (see my edit).
    And I was not implying the static keyword. I was saying that types are static. Ie std::map<T1, T2> where T1 and T2 are known (and never change).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #36
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Programmer_P View Post
    What?!
    It is already one line of code:
    Yes, because it is a function call just like that other one.

    You're doing something different there, obviously...
    Creating a map with strings as key values, and ints as mapped values, then calling a "getstringfromint" funtion? Btw, that's 2 lines...
    No, the map declaration was for clarity, that would be the original map. So "getstringfromint" would be a function to iterate through the map values to find the correct key. That would be in the case where you cannot use the two maps because the first one is not const (or effectively const).

    What would be the point of adding such a value to the original map?
    And how would you point it at the second map?
    Otherwise, how are you to keep the relationship between them? In your example program, there are only two so it is simple. However, in a program containing several mapped enums generated at runtime, unless you want to keep regenerating the parallel map (which we've already recognized as silly), you need something to "group" those variables. Namely the class of which the map is a part.

    I already have a class which contains the original map. You then call classObject.getEnumerationsMap() to get a copy of that map. Like I was saying earlier, I could easily create the second map as a member of the same class, and then add another function for retrieving that map, but I wrote the swap function so I can swap any map around, in case I need such a thing later on, I will have already written it.
    Ah, well you should definitely make the second map a member of the class then. The swap() function does not have to be part of the class in order to be used by it. Probably you can leave the second map uninitialized in case it is not needed.

    The purpose of the swap function is to be able to easily swap the key values and the mapped values around in any kind of map passed to the function, and it will then return a multimap containing all that stuff. That can be accomplished in one line of code like I just demonstrated.
    Yes, I understand all that.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #37
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Elysia View Post
    The types are static, aren't they? Then of course you can make a pointer to such a map, if you wanted. If I understand you correctly.
    My point was you could not add a member to a map<string,int> named "index_map" which points to another object (the inverted map), at least as far as I know. You could get away with it on a 32-bit system but obviously that is an ungood idea. Perhaps you could use a template or something instead of an int as the value, I have not tried that; otherwise you must wrap them both in something.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #38
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Something like this???
    Code:
    	std::map< std::string, std::tuple<int, std::map<int, std::string>*> > MyMap;
    Last edited by Elysia; 06-19-2010 at 11:50 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #39
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Elysia View Post
    Something like this???
    Code:
    	std::map< std::string, std::tuple<int, std::map<int, std::string>> > MyMap;
    Since you only need one such pointer per map (and not one for each element), that would be kind of a waste. You could do this I guess:

    Code:
    typedef union _val val;
    union _val {
          int n;
          std::map<string,val> *p;
    };
    Then you could set an element to an int (corresponding to the enum) OR use them as special pointers. This is still a bit of a waste on 64-bit.

    In C++ a class, or at least a struct wrapper, would be better/more orthodox methinks.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  10. #40
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by MK27 View Post
    Yes, because it is a function call just like that other one.
    Yep...so basically, your post didn't make sense, since you were saying "write a function, and it will be one line of code", and I had already did so.

    No, the map declaration was for clarity, that would be the original map.
    Yeah, I figured as much.
    So "getstringfromint" would be a function to iterate through the map values to find the correct key.
    Yes, but what would be the point of that, if you use the swap() function and you already have another map with the same content as the original, only the key values and the mapped values have been swapped? You can just pass the numerical value of the enumeration you want to retrieve the name of to at(), which is easy enough.
    That would be in the case where you cannot use the two maps because the first one is not const (or effectively const).
    Neither one of them are const (at least not in my example). A copy of the original map contained in the class generated by my program was gotten by calling the classObject.getEnumerationsMap() function, which admittedly returns a const& to a map<string, unsigned int>, but you could not have known that by looking at the code I posted. And anyway, the variable that the content of the referenced map was copied into at the function call, was not prefixed by the 'const' keyword, hence it should not be const. And when I created a multimap called "swappedMap" and copied the return value of the function swap, which returns a multimap by value, into swappedMap, it still was not const.

    Otherwise, how are you to keep the relationship between them? In your example program, there are only two so it is simple. However, in a program containing several mapped enums generated at runtime, unless you want to keep regenerating the parallel map (which we've already recognized as silly), you need something to "group" those variables. Namely the class of which the map is a part.
    Sorry, but that is flawed reasoning, IMO. First of all, say a given file had 5 enums in it (each one named something differently, with completely different enumerations, names and all, though it really wouldn't make a difference if something was the same as something else) and you ran ConvertEnumToStrings on said file. Now you have a generated file (most of the time, I use "results.h" as the filename) containing a separate class for each enum found in the file. So you're looking at 5 different classes in the generated file. Now, when you want to get something of a particular enum, you first include the results.h file in your program:

    Code:
    #include "results.h"
    (Note that the results file is always created inside the same directory as the file passed to ConvertEnumToStrings)
    Now you create an object of a class by the name of CnameofenumyouwanttodosomethingwithToStrings like this:

    Code:
    CnameofenumyouwanttodosomethingwithToStrings classObject;
    Ok, now you can get the map for that particular enum by doing:

    Code:
    map <string, unsigned int> enumerationsMap = classObject.getEnumerationsMap();
    Now, you can use the map in your program for whatever you need the enum for, by getting the numerical value of the enumeration you're interested in by just doing:

    Code:
    unsigned int numValue = enumerationsMap.at("enumerationname");
    You now have the relevant numerical value of the enumeration you're interested in, so you can use it for whatever you want (for example, passing it to a function expecting an enumeration of the said enum).
    Ok, now say you want the string name of the same enumeration. So, you do:
    Code:
    multimap <unsigned int, string> swappedMap = swap(enumerationsMap);
    You now have a multimap containing the same content as the enumerationsMap, only the key values and the mapped values have been swapped. So you can now access a specific enumeration's string name by doing something like:
    Code:
    string enumerationName = swappedMap.at(0);
    Now you can do whatever you want with that. Ok, now let's say you want to do something similiar with some of your other 4 enums. You will NOT use the same "classObject" object to get a map of another enum, since that is only an object of the first enum you're doing stuff with. You will create an object of the relevant class for that enum.
    And I see no problem with "regenerating the parallel map" as you put it, though in reality each enum which you chose to swap its map for would have its own relevant map and relevant swapped map.
    Ah, well you should definitely make the second map a member of the class then. The swap() function does not have to be part of the class in order to be used by it. Probably you can leave the second map uninitialized in case it is not needed.



    Yes, I understand all that.
    As for the swap() function, that is not a member of any of the classes. Like already mentioned, it is global, and only defined once in the results file generated by ConvertEnumToStrings.
    And like I already said, I noted from the start that I could make a second map as a member of the relevant class. But I chose not to, since I think having a swap function would be cool, and it would useful for any map I want to do that with. Anyways, its not likely you would want to swap the map around that often. And I provided another method for getting the name of an enumeration: getEnumerationName()
    Last edited by Programmer_P; 06-19-2010 at 12:07 PM.
    I'm an alien from another world. Planet Earth is only my vacation home, and I'm not liking it.

  11. #41
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Programmer_P View Post
    Yes, but what would be the point of that, if you use the swap() function and you already have another map with the same content as the original,
    As I said clearly quite a few times, I was describing an alternative to that, and then you kept asking me questions about it, so I continued to describe it. Obviously you would not use both methods.

    Neither one of them are const (at least not in my example).
    Sorry, I mean effectively "const", as in, are not changed after they are created. This is essential to the value of your method.

    Sorry, but that is flawed reasoning, IMO. [...] Now, you can use the map in your program for whatever you need the enum for
    So if the programmer using this interface wants to use several such maps in a program at once, you are leaving the burden on them to create a "swappedMap" for each map, and somehow keep track of this relationship.

    Let's say I have 3 different mapped enums. I create a swapped map for each of them:
    Code:
    multimap <unsigned int, string> swappedMap1 = swap(enumerationsMap1);
    multimap <unsigned int, string> swappedMap2 = swap(enumerationsMap2);
    multimap <unsigned int, string> swappedMap3 = swap(enumerationsMap3);
    Do you not see how it would be (much, much) better to be able to refer to this?
    Code:
    enumerationsMap1.swappedMap;
    This means the programmer does not have to number the variables in parallel (a very weak an inflexible method) or come up with there own derived class or a typedef like this:
    Code:
    typedef struct {
          map <string, unsigned int> enumerationsMap;
          multimap <unsigned int, string> swappedMap;
    } emaps;
    Which is what I would do if the class interface did not provide another means. Having to just remember which swappedMap is for what is only a minor hassle, what makes it a genuine problem is that is also limits what you can do with them -- for example, if you pass the map in as a variable to a function, you will have to pass both maps. Stuff like that is just a bad development practice -- you want to create options, not curtail them. At a certain point you will hit something this inflexibility will render impossible, meaning the programmer will have to create his/her own improptu interface, as above.

    As for the swap() function, that is not a member of any of the classes. Like already mentioned, it is global, and only defined once in the results file generated by ConvertEnumToStrings.
    Yes, as I said I do understand what you are doing: for the second time, a function does not need to be part of a class for the class to use that function.
    Last edited by MK27; 06-19-2010 at 12:14 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  12. #42
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by MK27 View Post
    My point was you could not add a member to a map<string,int> named "index_map" which points to another object (the inverted map), at least as far as I know.
    Perhaps I'm lagging behind, but I still don't understand why you would want a pointer to another map as a member of one map at all...
    I'm an alien from another world. Planet Earth is only my vacation home, and I'm not liking it.

  13. #43
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Programmer_P View Post
    Perhaps I'm lagging behind, but I still don't understand why you would want a pointer to another map as a member of one map at all...
    Yes, you are definitely missing the point here:

    Quote Originally Posted by Mk27
    Having to just remember which swappedMap is for what is only a minor hassle, what makes it a genuine problem is that is also limits what you can do with them -- for example, if you pass the map in as a variable to a function, you will have to pass both maps if they are needed. Stuff like that is just a bad development practice, because everytime you add some bit of functionality you have to change more code (add parameters, etc). You want to create options, not curtail them. At a certain point you will hit something this inflexibility will render impossible, meaning the programmer will have to create his/her own improptu interface, as above.
    The idea is to forsee the possibility. As a programmer, I'm just letting you know about the possibilities I see here, and the difficulties that will ensue if you don't forsee them.
    Last edited by MK27; 06-19-2010 at 12:20 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  14. #44
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by MK27 View Post
    As I said clearly quite a few times, I was describing an alternative to that, and then you kept asking me questions about it, so I continued to describe it. Obviously you would not use both methods.
    I don't recall you saying "quite clearly" that it was an alternative any time, but maybe that's just me...
    But yeah, I understand that its an alternative. I was just questioning if it was in fact better than my method.

    Sorry, I mean effectively "const", as in, are not changed after they are created. This is essential to the value of your method.
    Yeah, true. Like I already said, you should never try to modify either one of the maps (the original or the swapped). And anyone with any sense wouldn't, either. Why do it? There is no point.
    You already have a map for the enum. If you need a map for something else, create a different map. Its that simple.

    So if the programmer using this interface wants to use several such maps in a program at once, you are leaving the burden on them to create a "swappedMap" for each map, and somehow keep track of this relationship.
    Only for those maps they want to swap (which I doubt would be that often anyway). But yeah, that's the idea...

    And anyway, I already provide other methods for getting the string names of the enumerations:
    Code:
    const vector<string>& getEnumerationNames();
    and

    Code:
    const string& getEnumerationName(nameofenum enumeration);
    You can get any enumeration's name you want with the second method. And the first method returns a vector of the string names of ALL enumerations, so you can also do something with that as well.
    Let's say I have 3 different mapped enums. I create a swapped map for each of them:
    Code:
    multimap <unsigned int, string> swappedMap1 = swap(enumerationsMap1);
    multimap <unsigned int, string> swappedMap2 = swap(enumerationsMap2);
    multimap <unsigned int, string> swappedMap3 = swap(enumerationsMap3);
    Do you not see how it would be better to be able to refer to this:
    Code:
    enumerationsMap1.swappedMap;
    Actually, it would probably be something like:

    Code:
    enumerationsMap1.getSwappedMap();
    if I were going to do it that way. But yeah, the syntax might be a little better using the method you demonstrated. But both methods would work.
    And unless I see significant justification for a swapped version of the original enumerationsMap as a member of each enum's class, there's no reason to add that functionality in.
    This means the programmer does not have to number the variables in parallel (a very weak an inflexible method) or come up with there own derived class or a typedef like this:
    Code:
    typedef struct {
          map <string, unsigned int> enumerationsMap;
          multimap <unsigned int, string> swappedMap;
    } emaps;
    Which is what I would do if the class interface did not provide another means.
    Ok, yes, I see what you're saying. You seem to think that adding both maps (original and swapped) to a struct has some advantage over just keeping them both as a their map types, and doing stuff with them directly. I don't really see the point to such an approach.
    Either way, you still end up having to access a member of the map to do something useful with the map (i.e. retrieving a string name of an enumeration referred to by an unsigned int). And if I were coding and doing something like that with multiple enums, I'd think I would just write the code in a logical order, i.e.

    Code:
    //map the first enum
    //if you need to, swap the map
    //use the swapped map for something
    
    //map the second enum
    //if you need to, swap the map
    //use the swapped map for something
    as opposed to:

    Code:
    //map the first enum
    //if you need to, swap the map
    //add both maps to a struct
    //create an object of the struct
    //use the structObject.originalMap for something
    //use the structObject.swappedMap for something
    or

    Code:
    //get the map of the first enum
    //get the swapped map of the first enum
    //if you need to, use the swapped map for something
    Yes, as I said I do understand what you are doing: for the second time, a function does not need to be part of a class for the class to use that function.
    Exactly. I thought you were saying that the swap() function itself was a member function.
    Last edited by Programmer_P; 06-19-2010 at 12:33 PM.
    I'm an alien from another world. Planet Earth is only my vacation home, and I'm not liking it.

  15. #45
    Programming Ninja In-T...
    Join Date
    May 2009
    Posts
    827
    Quote Originally Posted by MK27 View Post
    Having to just remember which swappedMap is for what is only a minor hassle, what makes it a genuine problem is that is also limits what you can do with them -- for example, if you pass the map in as a variable to a function, you will have to pass both maps.
    Not really. I don't see why you would need to pass both maps to a function.
    You would have to give me an example of what the function would be for before I even consider that possibility. I just can't imagine a scenario where you would pass one map to a function, then pass a swapped map of that map to the same function...
    Stuff like that is just a bad development practice -- you want to create options, not curtail them. At a certain point you will hit something this inflexibility will render impossible, meaning the programmer will have to create his/her own improptu interface, as above.
    I did create options:

    Code:
    const vector<string>& getEnumerationNames();
    const string& getNameOfEnum();
    const int& getNumOfEnumerations();
    const string& getEnumerationName(nameofenum enumeration);
    const map<string, unsigned int> getEnumerationsMap();
    Sorry, but I can just not imagine why you would need anything other than those functions for dealing with the enumeration names and their associated numerical values. swap() is a luxury actually. The main reason I added it in to begin with, was in case I needed to swap other maps than the enumeration maps. The other reason was for the rare times when someone might want to swap the enumerations map around, for whatever reason.
    Last edited by Programmer_P; 06-19-2010 at 12:53 PM.
    I'm an alien from another world. Planet Earth is only my vacation home, and I'm not liking it.

Popular pages Recent additions subscribe to a feed