set_difference and set_intersection simultaneously

ぃ、小莉子 提交于 2019-12-22 04:57:13

问题


I'm wondering if there is any facility in the standard library to simultaneously compute the set intersection and set difference between two sorted ranges. Something with a signature along the lines of:

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 );

Such that after a call to decompose sets, result1 contains all the elements in [first1,last1) which are not in [first2,last2), result2 contains all the elements in [first2,last2) which are not in [first1,last1), and result3 contains all element which are common in [first1,last1) and [first2,last2).

The example implementations of set_difference and set_intersection from cplusplus.com seem like they can help me to create an efficient implementation which performs only one scan instead of three. If it's in the standard library, though, I'd hate to reinvent the wheel.

Example, by request:

Given two sets a={0, 1, 2, 3, 4} and b={2, 4, 5, 6} then I would like to build the following three sets:

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

回答1:


There's no standard library algorithm that will do it in a single scan but it's easy to write. The following looks correct and the output makes sense 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;
}



回答2:


There is no such function in STL, but there is set_symmetric_difference() that constructs a sorted sequence of the elements that are present in the first sequence but not present in the second, and those elements present in the second sequence are not present in the first.




回答3:


Here is another alternative, which is using callbacks for maximum flexibility.

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);
}

This has the following advantages:

  • Output lists are optional now
  • Output can be a different type (transform)
  • Common items can be further processed in tandem (additional compare)

"Real world" example:

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
                     );  
}


来源:https://stackoverflow.com/questions/18164426/set-difference-and-set-intersection-simultaneously

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!