What is the best way to use two keys with a std::map?

后端 未结 9 1815
你的背包
你的背包 2021-01-30 03:54

I have a std::map that I\'m using to store values for x and y coordinates. My data is very sparse, so I don\'t want to use arrays or vectors, which would result in

相关标签:
9条回答
  • 2021-01-30 04:28

    What are the requirements on a class that is to be used as the key?

    The map needs to be able to tell whether one key's value is less than another key's value: by default this means that (key1 < key2) must be a valid boolean expression, i.e. that the key type should implement the 'less than' operator.

    The map template also implements an overloaded constructor which lets you pass-in a reference to a function object of type key_compare, which can implement the comparison operator: so that alternatively the comparison can be implemented as a method of this external function object, instead of needing to be baked in to whatever type your key is of.

    0 讨论(0)
  • 2021-01-30 04:29

    First and foremost, ditch the string and use 2 ints, which you may well have done by now. Kudos for figuring out that a tree is the best way to implement a sparse matrix. Usually a magnet for bad implementations it seems.

    FYI, a triple compound key works too, and I assume a pair of pairs as well.

    It makes for some ugly sub-scripting though, so a little macro magic will make your life easier. I left this one general purpose, but type-casting the arguments in the macro is a good idea if you create macros for specific maps. The TresKey12 is tested and running fine. QuadKeys should also work.

    NOTE: As long as your key parts are basic data types you DON'T need to write anything more. AKA, no need to fret about comparison functions. The STL has you covered. Just code it up and let it rip.

    using namespace std;    // save some typing
    #define DosKeys(x,y)      std::make_pair(std::make_pair(x,y))
    #define TresKeys12(x,y,z) std::make_pair(x,std::make_pair(y,z))
    #define TresKeys21(x,y,z) std::make_pair(std::make_pair(x,y),z))
    
    #define QuadKeys(w,x,y,z) std::make_pair(std::make_pair(w,x),std::make_pair(y,z))
    
    
    map<pair<INT, pair<ULLNG, ULLNG>>, pIC_MESSAGE> MapMe;
    MapMe[TresKey12(Part1, Part2, Part3)] = new fooObject;
    

    If someone wants to impress me, show me how to make a compare operator for TresKeys that doesn't rely on nesting pairs so I can use a single struct with 3 members and use a comparison function.

    PS: TresKey12 gave me problems with a map declared as pair,z as it makes x,pair, and those two don't play nice. Not a problem for DosKeys, or QuadKeys. If it's a hot summer Friday though, you may find an unexpected side-effect of typing in DosEquis ... err.. DosKeys a bunch of times, is a thirst for Mexican beer. Caveat Emptor. As Sheldon Cooper says, "What's life without whimsy?".

    0 讨论(0)
  • 2021-01-30 04:35

    I think for your use case, std::pair, as suggested in David Norman's answer, is the best solution. However, since C++11 you can also use std::tuple. Tuples are useful if you have more than two keys, for example if you have 3D coordinates (i.e. x, y, and z). Then you don't have to nest pairs or define a comparator for a struct. But for your specific use case, the code could be written as follows:

    int main() {
        using tup_t = std::tuple<int, int>;
        std::map<tup_t, int> m;
    
        m[std::make_tuple(78, 26)] = 476;
        tup_t t = { 12, 45 }; m[t] = 102;
    
        for (auto const &kv : m)
            std::cout << "{ " << std::get<0>(kv.first) << ", "
                              << std::get<1>(kv.first) << " } => " << kv.second << std::endl;
        return 0;
    }
    

    Output:

    { 12, 45 } => 102
    { 78, 26 } => 476

    Note: Since C++17 working with tuples has become easier, espcially if you want to access multiple elements simultaneously. For example, if you use structured binding, you can print the tuple as follows:

    for (auto const &[k, v] : m) {
        auto [x, y] = k;
        std::cout << "{ " << x << ", " << y << " } => " << v << std::endl;
    }
    

    Code on Coliru

    0 讨论(0)
  • 2021-01-30 04:36

    Use std::pair<int32,int32> for the key:

    std::map<std::pair<int,int>, int> myMap;
    
    myMap[std::make_pair(10,20)] = 25;
    std::cout << myMap[std::make_pair(10,20)] << std::endl;
    
    0 讨论(0)
  • 2021-01-30 04:42

    Hope you will find it useful:

    map<int, map<int, int>> troyka = { {4, {{5,6}} } };
    troyka[4][5] = 7;
    
    0 讨论(0)
  • 2021-01-30 04:45

    I usually solve this kind of problem like this:

    struct Point {
        int x;
        int y;
    };
    
    inline bool operator<(const Point& p1, const Point& p2) {
        if (p1.x != p2.x) {
            return p1.x < p2.x;
        } else {
            return p1.y < p2.y;
        }
    }
    
    0 讨论(0)
提交回复
热议问题