【问题标题】:How to find the difference of two maps? [closed]如何找到两张地图的差异? [关闭]
【发布时间】:2014-06-18 02:10:43
【问题描述】:

我正在尝试实现与 set_intersection 和 set_difference 类似的功能,但使用地图作为我的日期类型进行分配。我能够找到交集,但差异函数的输出不是我应该期待的,我不知道为什么。我正在使用的两个功能如下。

map<string, int> Group::Intersection(map<string, int> &tempSet, map<string, int> &currentSet){
    map<string, int>::const_iterator input_iterator;
    map<string, int> result;
    typename map<string, int>::const_iterator it1 = tempSet.begin();
    typename map<string, int>::const_iterator it2 = currentSet.begin();

    while (it1 != tempSet.end() && it2 != currentSet.end())
    {
        if (it1->first < it2->first)
            ++it1;
        else if (it2->first < it1->first)
            ++it2;
        else{
            result.insert(make_pair(it2->first, min(it1->second, it2->second)));
            ++it1;
            ++it2;
        }
    }

    return result;
}

map<string, int> Group::Difference(map<string, int> &tempSet, map<string, int> &currentSet){
    map<string, int>::const_iterator input_iterator;
    map<string, int> result;
    typename map<string, int>::const_iterator it1 = tempSet.begin();
    typename map<string, int>::const_iterator it2 = currentSet.begin();

    while (it1 != tempSet.end() && it2 != currentSet.end())
    {
        if (it1->first < it2->first){
            result.insert(make_pair(it1->first, abs(it1->second - it2->second)));
            ++it1;
        }
        else if (it2->first < it1->first){
            result.insert(make_pair(it2->first, abs(it1->second - it2->second)));
            ++it2;
        }
        else{            
            ++it1;
            ++it2;
        }
    }
    return result;
}

使用这两个列表:

cat 5
dog 4
bear 2
dinosaur 1

cat 6
dog 4
snake 3
lion 4

我收到了猫 5 和狗 4 的交集,但差异给了我熊 4 和恐龙 3。据我所知,这是从第一个地图中获取两个键并将它们与第二张地图,但我无法确定这是我的迭代还是我将键/值放入新地图时。任何建议都将不胜感激,因为我觉得这应该是一个我无法弄清楚的简单解决方案。

【问题讨论】:

标签: c++ map


【解决方案1】:

您的集合差异的问题在于,在您完成迭代后,任一列表中都可能存在元素。所以在你的诡计循环之后,你需要添加:

while (it1 != tempSet.end()) //add remaining elements from first map
{
  result.insert(*it1++);
}
while (it2 != currentSet.end()) //add remaining elements from second map
{
  result.insert(*it2++);
}

【讨论】:

    【解决方案2】:

    您错误地处理了结束情况。一旦到达 either 列表的末尾,您就会停止,这会导致您省略条目。 (考虑一个列表为空的简单情况。您根本不会输出任何内容。)

    【讨论】:

      【解决方案3】:

      这是一个答案,也是寻求澄清的尝试。

      寻求澄清

      假设你有:

      std::map<std::string, int> c1 = {{"a", 10}, {"b", 20}, {"c", 30}, {"d", 40}, {"f", 40}};
      std::map<std::string, int> c2 = {{"b", 200}, {"c", 300}, {"d", 400}, {"e", 500}};
      
      std::map<std::string, int> c3 = map_intersect(c1, c2);
      std::map<std::string, int> c4 = map_difference(c1, c2);
      

      你期望c3 是什么?

      {{"b", 20}, {"c", 30}, {"d", 40}}
      

      {{"b", 200}, {"c", 300}, {"d", 400}}
      

      该问题的答案将决定您将如何实现map_intersect 函数。

      你期望c4 是什么?期望它是更自然的:

      {{"a", 10}, {"f", 40}}
      

      有一些假设的解决方案

      假设您希望上述c3 的值为:

      {{"b", 20}, {"c", 30}, {"d", 40}}
      

      上面c4的值为:

      {{"a", 10}, {"f", 40}}
      

      以下实现在我的测试中有效:

      std::map<std::string, int> map_intersect(std::map<std::string, int> const& c1,
                                               std::map<std::string, int> const& c2)
      {
         std::map<std::string, int> ret;
         std::map<std::string, int>::const_iterator iter = c2.begin();
         std::map<std::string, int>::const_iterator end = c2.end();
         for ( ; iter != end; ++iter )
         {
            if ( c1.find(iter->first) != c1.end() )
            {
               ret[iter->first] = iter->second;
            }
         }
      
         return ret;
      }
      
      std::map<std::string, int> map_difference(std::map<std::string, int> const& c1,
                                                std::map<std::string, int> const& c2)
      {
         std::map<std::string, int> ret = c1;
         std::map<std::string, int>::const_iterator iter = c2.begin();
         std::map<std::string, int>::const_iterator end = c2.end();
         for ( ; iter != end; ++iter )
         {
            if ( c1.find(iter->first) != c1.end() )
            {
               ret.erase(iter->first);
            }
         }
         return ret;
      }
      

      【讨论】:

        【解决方案4】:

        你需要定义你想要的操作的预期结果,但是有一些东西有点味道:

            if (it1->first < it2->first){
                result.insert(make_pair(it1->first, abs(it1->second - it2->second)));
                ++it1;
            }
        

        创建一个以it1-&gt;first 为索引的条目是否有意义,其中包含通过减去与it1-&gt;first 关联的原始值和一些不相关的值而获得的数字?在这种情况下,键不同,可能并不意味着聚合值。

            else{            
                ++it1;
                ++it2;
            }
        

        如果两个映射都包含相同的键,你就忽略它吗?你应该检查相关的值吗?在这种情况下,合并两张地图的结果实际上是有意义的。除此之外,我不确定您是否要使用绝对值。在我的书中1 - 55 - 1 不同。保留该符号可以帮助您在以后确定两个输入中的哪一个具有更大的键值。

        while (it1 != tempSet.end() && it2 != currentSet.end()) {
           …
        }
        

        当其中一张地图完成时会发生什么?您想忽略其他地图中的值吗?考虑退化的情况:具有 N 个键值对的映射和一个空映射,应该有什么区别,一个 empty 映射?这就是你的算法正在生成的。

        除了算法本身,我建议您采用有条不紊的方法进行测试。构建小型测试用例,自下而上:首先是两个空映射,然后一个空映射一个值,然后两个空一个值相同/不同,值相同/不同,然后……通过从地面构建测试用例起来,您将有更大的机会在算法中挑出问题。例如,一个地图中有一个元素而另一个(两个方向)没有元素的测试用例会让您考虑循环中的终止条件。拥有两个具有相同键和相同/不同值的集合会提示匹配键是否存在问题,等等。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-12-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多