为什么简单算术减法在"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。 如果我改变数组的顺序,那么代码就可以正常工作。我在这里做错了什么?

您有两个重大错误:

  1. 正在处理数据的副本(已在注释中标识)。使用引用意味着更改将反映在原始容器中,而不是在副本超出范围时被丢弃。

    for (auto& i : mapcheckA) { // 添加 &

  2. 未定义的行为 在您的“其他”情况下,您删除了迭代中的当前元素,使迭代器 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 的结果。