Your approach (once corrected, as VHS's answer did) could be fine for a small number of points, but, with a bigger set of data, an O(N2) algorithm could be too inefficient.
You can take advantage of the average costant time that takes inserting an element in a std::unordered_set
, even if you are required to write a comparison function and an hash function for your class.
The algorithm presented below uses two unordered_set's:
uniques
ends up storing all the elements that are present in the source container, without repetitions.
repeated
stores a unique instance of only the elements that are present multiple times.
An element is copied to the output only if it's already present in uniques
, but not in repeated
.
#include <iostream>
#include <vector>
#include <unordered_set>
#include <algorithm>
#include <iterator>
struct point
{
int x, y;
bool operator== (point const& b) const
{
return x == b.x && y == b.y;
}
};
namespace std {
template<> struct hash<point>
{
std::size_t operator() (point const& p) const
{
return (std::hash<int>{}(p.x) << 1) ^ std::hash<int>{}(p.y);
}
};
}
std::ostream& operator<< (std::ostream& os, point const& pt)
{
return os << '(' << pt.x << ", " << pt.y << ')';
}
template<class InputIt, class OutputIt>
OutputIt copy_repeated_values(InputIt first, InputIt last, OutputIt dest)
{
using value_type = typename InputIt::value_type;
std::unordered_set<value_type> uniques, repeated;
return std::copy_if(
first, last, dest, [&] (value_type const& value) {
return
not uniques.insert(value).second &&
repeated.insert(value).second;
}
);
}
int main()
{
std::vector<point> points {
{3,5}, {4,2}, {2,4}, {3,5}, {7,8}, {7,8}, {4,2}, {7,8}, {3,5}, {2,4}
};
copy_repeated_values(
std::begin(points), std::end(points),
std::ostream_iterator<point>(std::cout, " ")
);
std::cout << '\n';
}
The output is:
(3, 5) (7, 8) (4, 2) (2, 4)