4

Given 2 sets (C++) is there a convenient way to get the size of the intersection without any alocations (as std::set_intersection does)

Sure, I could copy the implementation minus the assignment but I always rather not re-invent the wheel

int count = 0;
while (first1!=last1 && first2!=last2)
{
    if (*first1<*first2) ++first1;
    else if (*first2<*first1) ++first2;
    else {
        count++; ++first1; ++first2;
    }
 }

I was considering using std::set_intersection and pass a "counting" interator...?

aivision2020
  • 619
  • 6
  • 14
  • which allocation in std::set_intersection do you mean? – 4pie0 Sep 10 '14 at 11:46
  • @0d0a `std::set_intersection` copies the common elements into the output iterator, and that will typically require allocations for the container, and possibly also allocations for the elements being copied. –  Sep 10 '14 at 11:52
  • 1
    Your code looks correct, and that's how I'd do it. You might be able to construct a "counting" iterator that performs no allocation, but I doubt it would be simpler than this. – Beta Sep 10 '14 at 11:55
  • it looks like you just need to implement operator++() for a class and pass as fake output iterator to set_intersection – 4pie0 Sep 10 '14 at 17:26
  • ~7 years down the lane, do we have any better luck with c++17/20 features ? or maybe any lambda trickery? – vaibhavatul47 Feb 13 '21 at 15:04

2 Answers2

5

With some help from Boost Iterator library and C++14's generic lambdas:

#include <set>
#include <algorithm>
#include <iostream>
#include <boost/function_output_iterator.hpp>

int main()
{
    std::set<int> s1 { 1,2,3,4 };
    std::set<int> s2 { 3,4,5,6 };

    int i = 0;
    auto counter = [&i](auto){ ++i; };  // C++14
 // auto counter = [&i](int ){ ++1; };  // C++11
 // pre C++11, you'd need a class with overloaded operator()

    std::set_intersection(
        s1.begin(), s1.end(), s2.begin(), s2.end(),
        boost::make_function_output_iterator(counter)
    );

    std::cout << i;
}

Output is 2.

jrok
  • 54,456
  • 9
  • 109
  • 141
0

Another solution might be to look inside into std::set_intersection code and implement your counter class to reflect it's behavior. This depends on usage of operator++, std::set_intersection uses prefix, but I have added also postfix operator.

#include <set>
#include <algorithm>
#include <iostream>

class CountIt {
    public:
    CountIt() : storage(0), counter(0) {}
    CountIt& operator++()
    {
        ++counter;
        return *this;
    }
    CountIt operator++(int)
    {
        CountIt oldValue = *this;
        return ++( *this);
    }
    int& operator*() { return storage;}
    int storage, counter;
};

int main()
{
    std::set<int> s1 { 1,2,3,4 };
    std::set<int> s2 { 3,4,5,6 };

   CountIt const & c = std::set_intersection(
        s1.begin(), s1.end(), s2.begin(), s2.end(),
        CountIt()
    );

    std::cout << c.counter;  // 2, hopefuly
}

http://ideone.com/j8GrBB

4pie0
  • 29,204
  • 9
  • 82
  • 118