同时set_difference和set_intersection

时间:2013-08-10 17:16:05

标签: c++ stl std

我想知道标准库中是否有任何工具可以同时计算集合交集并设置两个有序范围之间的差异。带有签名的东西:

template <class Input1, class Input2, 
          class Output1, class Output2, class Output3>
Output3 decompose_sets (Input1 first1, Input1 last1,
                        Input2 first2, Input2 last2,
                        Output1 result1, Output2 result2,
                        Output3 result3 );

这样,在致电decompose sets后,result1包含[first1,last1)中不在[first2,last2)中的所有元素,result2包含所有元素不在[first2,last2)中的[first1,last1)result3包含[first1,last1)[first2,last2)中常见的所有元素。

来自cplusplus.com的set_differenceset_intersection的示例实现似乎可以帮助我创建一个只执行一次扫描而不是三次扫描的高效实现。但是,如果它在标准库中,我不想重新发明轮子。

示例,请求:

给定两组a = {0,1,2,3,4}和b = {2,4,5,6}然后我想构建以下三组:

  • only_a = {0,1,3}
  • only_b = {5,6}
  • common = {2,4}

3 个答案:

答案 0 :(得分:3)

没有标准的库算法可以在一次扫描中完成,但它很容易编写。以下看起来正确,输出有意义here on ideone.com

template <class Input1, class Input2,
            class Output1, class Output2, class Output3>
Output3 decompose_sets(Input1 first1, Input1 last1,
                    Input2 first2, Input2 last2,
                    Output1 result1, Output2 result2,
                    Output3 result3)
{
    while (first1 != last1 && first2 != last2) {
        if (*first1 < *first2) {
            *result1++ = *first1++;
        } else if (*first2 < *first1) {
            *result2++ = *first2++;
        } else {
            *result3++ = *first1++;
            ++first2; // skip common value in set2
        }
    }
    std::copy(first1, last1, result1);
    std::copy(first2, last2, result2);
    return result3;
}

答案 1 :(得分:1)

STL中没有这样的函数,但是set_symmetric_difference()构造了第一个序列中存在但第二个序列中不存在的元素的排序序列,第二个序列中存在的元素是没有出现在第一个。

答案 2 :(得分:0)

这是另一种选择,它使用回调来获得最大的灵活性。

template <class Input1, class Input2
            , class FuncAdd, class FuncRm, class FuncSame, class Comp>
void set_difference_adv(Input1 firstOld, Input1 lastOld
                        ,Input2 firstNew, Input2 lastNew
                        ,FuncAdd onadded, FuncRm onremoved, FuncSame onsame, Comp comp)
{
  while (firstOld != lastOld && firstNew != lastNew) {

    if (comp(*firstOld, *firstNew)) {
      onremoved(*firstOld++);
    } else if (comp(*firstNew, *firstOld)) {
      onadded(*firstNew++);
    } else {
      onsame(*firstOld++, *firstNew++);
    }
  }

  std::for_each(firstOld, lastOld, onremoved);
  std::for_each(firstNew, lastNew, onadded);
}

这具有以下优点:

  • 输出列表现在是可选的
  • 输出可以是不同类型(转换)
  • 可以进一步处理常见项目(附加比较)

“真实世界”的例子:

int main()
{
  using File = std::pair<std::string, int>;

  std::vector<File> files1{{"file1", 12}, {"file3", 8}, {"file4", 2}, {"file5", 10}};
  std::vector<File> files2{{"file1", 12}, {"file2", 5}, {"file3", 8}, {"file4", 33}};

  const auto less = [](const auto& o, const auto& n) { return o.first < n.first; };

  std::vector<std::string> addedNames;
  std::vector<File> changedFiles;

  set_difference_adv(std::cbegin(files1), std::cend(files1)
                     ,std::cbegin(files2), std::cend(files2)
                     , [&addedNames](const auto& val){ addedNames.push_back(val.first); } //< added (transform)
                     , [](const auto& val) {} //< removed (ignore)
                     , [&changedFiles](const auto& o, const auto& n){ if(n.second > o.second) changedFiles.push_back(n); } //< "same" (further compare)
                     , less
                     );  
}