为啥简单的算术减法在“if”条件下不起作用?

Posted

技术标签:

【中文标题】为啥简单的算术减法在“if”条件下不起作用?【英文标题】:Why does the simple arithmetic subtraction not work in the "if" condition?为什么简单的算术减法在“if”条件下不起作用? 【发布时间】:2020-07-08 11:57:18 【问题描述】:

我有 2 个数组,其中包含元素。我使用散列来获取每个元素出现多次的频率。 mapcheckA 包含第一个数组元素的频率,mapcheckB 包含另一个数组的频率。我正在尝试从两个无序地图中删除/擦除任何重复的元素。这是执行此操作的代码:

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。 如果我更改数组的顺序,则代码可以正常工作。我在这里做错了什么?

【问题讨论】:

当我打印键值对时,对于上述 2 个数组,输出为: 对于 arrayA:4 2 1 4 对于 arrayB:3 2 2 2 在循环 for (auto i : mapcheckA) 中,您正在对元素的副本进行操作,您的意思是要对实际对象 (for (auto&amp; i : mapcheckA)) 的引用进行操作吗? @AlgirdasPreidžius 在i 之前在for (auto i: mapcheckA) 中插入&amp; 后,问题就解决了。但我不明白为什么以及如何解决它。 @BennyK 但它工作正常。当第二个数组中某个元素的频率大于第一个时,输出是正确的。当第一个数组中的频率大于第二个时,我遇到了问题。 @Thomas Sablik - 抱歉,错过了“无序地图”部分。 【参考方案1】:

您有两个重大错误:

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

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

    未定义的行为 在您的“其他”情况下,您删除迭代中的当前元素,使迭代器 i 无效,但循环继续增加 i。程序状态不确定,不能这样做。

不幸的是,对于范围广泛的 for 循环,没有好的方法可以做到这一点。您的选择:

记住键(或迭代器)以备后用,并在循环后删除它们

手动滚动循环以进行手动迭代器递增:

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 循环中进行,因为其中一个使用 ++,而另一个获取调用擦除的结果。

【讨论】:

以上是关于为啥简单的算术减法在“if”条件下不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

Alter Table 在 MS Access 64 位下不起作用。为啥?

为啥 webview_flutter 在添加到应用程序(iOS)的情况下不起作用?

为啥 selectAnnotation 在这种情况下不起作用?

为啥消息处理程序在调试模式下不起作用?

为啥小写 [i] 在可视块模式下不起作用?

为啥转换在我的情况下不起作用