为什么简单算术减法在"if"条件下不起作用?
Why does the simple arithmetic subtraction not work in the "if" condition?
我有 2 个包含元素的数组。我使用散列法来获取出现不止一次的每个元素的频率。 mapcheckA
包含第一个数组元素的频率,mapcheckB
包含另一个数组的频率。我正在尝试 delete/erase 来自两个无序映射的元素的任何重复项。这是执行此操作的代码:
for (auto i : mapcheckA) {
if (mapcheckB.find(i.first) != mapcheckB.end()) {
if (i.second >=
mapcheckB.find(i.first)
->second) { // This block of code doesn't work as expected
i.second -= mapcheckB.find(i.first)->second;
mapcheckB.erase(i.first);
} else {
mapcheckB.find(i.first)->second -= i.second;
mapcheckA.erase(i.first);
}
}
}
for (auto i1 : mapcheckA) {
cout << i1.first << "\t" << i1.second << endl;
}
for (auto i : mapcheckB) {
cout << i.first << "\t" << i.second << endl;
}
当我输入元素时,第一个数组包含的元素比第二个数组中的元素出现频率更高,如下所示:
arrayA = [ 1, 1, 1, 1, 4, 4 ]; // Here frequency of "1" is 4.
arrayB = [ 2, 2, 1, 1, 3, 3 ]; // Here frequency of "1" is 2.
在这种情况下,“if”条件中的代码块不会将 1 的频率更改为 2。
如果我改变数组的顺序,那么代码就可以正常工作。我在这里做错了什么?
您有两个重大错误:
正在处理数据的副本(已在注释中标识)。使用引用意味着更改将反映在原始容器中,而不是在副本超出范围时被丢弃。
for (auto& i : mapcheckA) { // 添加 &
未定义的行为
在您的“其他”情况下,您删除了迭代中的当前元素,使迭代器 i 无效,但循环继续递增 i。程序状态不确定,不能这样做。
不幸的是,对于范围循环,没有好的方法可以做到这一点。您的选择:
记住键(或迭代器)以备后用,并在循环后删除它们
手动循环递增迭代器:
for (auto i = begin(mappedA), e = end(mappedA); i != e; ) {
if (...) {
...
++i;
}
else {
...
i = mappedA.erase(i);
}
}
此外,您可以考虑使用 c++ 结构化绑定 来提高代码的可读性并减少相同的查找。将所有这些放在一起:
for (auto iterA = begin(mapcheckA), endA = end(mapcheckA); iterA != endA; ) {
auto& [keyA, valueA] = *iterA;
if (auto iterB = mapcheckB.find(keyA); iterB != end(mapcheckB)) {
auto& [keyB, valueB] = *iterB;
if (valueA >= valueB) {
valueA -= valueB;
mapcheckB.erase(iterB);
++iterA;
} else {
valueB -= valueA;
iterA = mapcheckA.erase(iterA);
}
}
}
注意:if 的两半都更新了 iterA 而不是在 for 循环中进行,因为一个使用 ++ 而另一个采用调用 erase 的结果。
我有 2 个包含元素的数组。我使用散列法来获取出现不止一次的每个元素的频率。 mapcheckA
包含第一个数组元素的频率,mapcheckB
包含另一个数组的频率。我正在尝试 delete/erase 来自两个无序映射的元素的任何重复项。这是执行此操作的代码:
for (auto i : mapcheckA) {
if (mapcheckB.find(i.first) != mapcheckB.end()) {
if (i.second >=
mapcheckB.find(i.first)
->second) { // This block of code doesn't work as expected
i.second -= mapcheckB.find(i.first)->second;
mapcheckB.erase(i.first);
} else {
mapcheckB.find(i.first)->second -= i.second;
mapcheckA.erase(i.first);
}
}
}
for (auto i1 : mapcheckA) {
cout << i1.first << "\t" << i1.second << endl;
}
for (auto i : mapcheckB) {
cout << i.first << "\t" << i.second << endl;
}
当我输入元素时,第一个数组包含的元素比第二个数组中的元素出现频率更高,如下所示:
arrayA = [ 1, 1, 1, 1, 4, 4 ]; // Here frequency of "1" is 4.
arrayB = [ 2, 2, 1, 1, 3, 3 ]; // Here frequency of "1" is 2.
在这种情况下,“if”条件中的代码块不会将 1 的频率更改为 2。 如果我改变数组的顺序,那么代码就可以正常工作。我在这里做错了什么?
您有两个重大错误:
正在处理数据的副本(已在注释中标识)。使用引用意味着更改将反映在原始容器中,而不是在副本超出范围时被丢弃。
for (auto& i : mapcheckA) { // 添加 &
未定义的行为 在您的“其他”情况下,您删除了迭代中的当前元素,使迭代器 i 无效,但循环继续递增 i。程序状态不确定,不能这样做。
不幸的是,对于范围循环,没有好的方法可以做到这一点。您的选择:
记住键(或迭代器)以备后用,并在循环后删除它们
手动循环递增迭代器:
for (auto i = begin(mappedA), e = end(mappedA); i != e; ) {
if (...) {
...
++i;
}
else {
...
i = mappedA.erase(i);
}
}
此外,您可以考虑使用 c++ 结构化绑定 来提高代码的可读性并减少相同的查找。将所有这些放在一起:
for (auto iterA = begin(mapcheckA), endA = end(mapcheckA); iterA != endA; ) {
auto& [keyA, valueA] = *iterA;
if (auto iterB = mapcheckB.find(keyA); iterB != end(mapcheckB)) {
auto& [keyB, valueB] = *iterB;
if (valueA >= valueB) {
valueA -= valueB;
mapcheckB.erase(iterB);
++iterA;
} else {
valueB -= valueA;
iterA = mapcheckA.erase(iterA);
}
}
}
注意:if 的两半都更新了 iterA 而不是在 for 循环中进行,因为一个使用 ++ 而另一个采用调用 erase 的结果。