作为 std::map 键的唯一结构不插入所有数据

Unique struct as std::map key not inserting all data

我正在尝试用“关键数据”填充不同的地图,然后将“关键数据”作为关键提取到主地图中。然而;主地图正在跳过几个唯一的条目,就好像已经有一个现有的密钥一样。

谁能解释一下其余键的情况以及为什么它们没有插入到主映射中。

这是我用作打开主地图的密钥的结构。 (是的,我知道我可以使用 std::tie 作为运算符重载。我的项目约束是 c++98 ):

struct MyStruct
{
    std::string stringVar;
    unsigned unsigVar;
    float floatVar;

    bool operator<(MyStruct const &rhs) const
    {
        return ((this->unsigVar  > rhs.unsigVar)  ||
                (this->stringVar > rhs.stringVar) ||  
                (this->floatVar  > rhs.floatVar));
    }   
};

所有“关键地图”和主地图

std::map< std::string, std::vector<std::string> > stringMap;
std::map< std::string, std::vector<unsigned> > unsigMap;
std::map< std::string, std::vector<float> > floatMap;
std::map<MyStruct, int> masterMap;

获取关键数据并推入向量

std::string keys[3] = {"key1", "key2", "key3"};   

std::vector<std::string> strVector;
std::vector<unsigned> unsigVector;
std::vector<float> floatVector;

strVector.push_back("str1");
strVector.push_back("str2");

unsigVector.push_back(10);
unsigVector.push_back(20);

floatVector.push_back(36.0);
floatVector.push_back(37.0);

将矢量数据存储到“键映射”中

for (int i=0; i < sizeof(keys)/sizeof(keys[0]); i++)
{
   stringMap.insert( std::make_pair(keys[i], strVector) ); 
   unsigMap.insert( std::make_pair(keys[i], unsigVector) );
   floatMap.insert( std::make_pair(keys[i], floatVector) );
}

然后我遍历所有地图并将“关键数据”插入带有虚假数据的主地图

// iterators for data maps
std::map< std::string, std::vector<std::string> >::iterator stringIter;
std::map< std::string, std::vector<unsigned> >::iterator unsigIter;
std::map< std::string, std::vector<float> >::iterator floatIter;

// point to first key only
stringIter = stringMap.find(keys[0]);
unsigIter = unsigMap.find(keys[0]);
floatIter = floatMap.find(keys[0]);

// loop through data maps and store into master map
for (int i=0; i < stringIter->second.size(); i++)
{
    for (int j=0; j < unsigIter->second.size(); j++)
    {
        for (int k=0; k < floatIter->second.size(); k++)
        {
            // create struct to easily store into master map
            MyStruct myStruct;
            myStruct.stringVar = stringIter->second[i];
            myStruct.unsigVar = unsigIter->second[j];
            myStruct.floatVar = floatIter->second[k];

            // bogus data
            int data = 3;

            masterMap.insert( std::make_pair(myStruct, data) );

            std::map<MyStruct, int>::iterator masterIter;
            masterIter = masterMap.find(myStruct);

            //make sure all keys & data were inserted
            if (masterIter != masterMap.end())
            {
                std::cout << stringIter->second[i] << "\t"
                          << unsigIter->second[j] << "\t"
                          << floatIter->second[k] << "\t"
                          << masterIter->second <<std::endl;
            }
        }
    }
}

这是我得到的:

str1    10      36      3
str1    10      37      3
str1    20      37      3
str2    20      37      3

这是我期望得到的:

str1    10      36      3
str1    10      37      3
str1    20      36      3 <--- missing
str1    20      37      3
str2    10      36      3 <--- missing
str2    10      37      3 <--- missing
str2    20      36      3 <--- missing
str2    20      37      3

您可能打算进行如下比较:

bool operator<(MyStruct const &rhs) const
    {
        return ((unsigVar  < rhs.unsigVar)  ||
                ((unsigVar  == rhs.unsigVar) && 
                (stringVar < rhs.stringVar) ||  
                ((stringVar == rhs.stringVar) && 
                (floatVar  < rhs.floatVar))));
    }   

您的比较函数不正确,因为以下两个比较都是正确的:(1, "b") < (2, "a") 和 (2, "a") < (1, "b")

  • 1 < 2 或“b”<“a”
  • 2 < 1 或“a”<“b”

所以只添加了其中一个键。

添加到@steger 的答案中,您可以使用元组生成比较函数:

bool operator<(MyStruct const &rhs) const {
   return std::make_tuple(unsigVar, stringVar, floatVar) < std::make_tuple(
      rhs.unsigVar, rhs.stringVar, rhs.floatVar
   );
}

元组比较进行词法比较。参见 https://en.cppreference.com/w/cpp/utility/tuple/operator_cmp

中的第三点

请注意浮点比较充满问题:https://www.boost.org/doc/libs/1_63_0/libs/math/doc/html/math_toolkit/float_comparison.html

您的 operator< 不满足 Strict Weak 订购要求。

通过从 operator==,!=,<,<=,>,>=,<=>(std::tuple) 复制 std::tuple 的示例实现,您可以将其制作成如下所示。

实现模式不使用相等比较来允许浮点比较出现在任何地方。即使你的浮点数比较在最后,我也保留了这个模式,因为它很容易阅读和扩展。

它按降序排列,因为它看起来像您想要的问题:

bool operator<(MyStruct const &rhs) const {
    if(rhs.unsigVar < unsigVar) return true;
    if(unsigVar < rhs.unsigVar) return false;

    // the "unsigVar"s are equal

    if(rhs.stringVar < stringVar) return true;
    if(stringVar < rhs.stringVar) return false;

    // the "stringVar"s are equal

    // the last one only needs one comparison:
    return rhs.floatVar < floatVar;
}