作为 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;
}
我正在尝试用“关键数据”填充不同的地图,然后将“关键数据”作为关键提取到主地图中。然而;主地图正在跳过几个唯一的条目,就好像已经有一个现有的密钥一样。
谁能解释一下其余键的情况以及为什么它们没有插入到主映射中。
这是我用作打开主地图的密钥的结构。 (是的,我知道我可以使用 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;
}