Can someone point me, please, if where is some algorithms within STL to compute difference and intersection per one call in manner of unix comm utility?
int main()
{
//For example we have two sets on input
std::set<int>a = { 1 2 3 4 5 };
std::set<int>b = { 3 4 5 6 7 };
std::call_some_func(a, b, ... );
//So as result we need obtain 3 sets
//x1 = {1, 2} // present in a, but absent in b (difference)
//x2 = {3, 4, 5} // present on both sets (intersection)
//x3 = {6, 7} // present in b, but absent in a
}
My current implementation uses 2 calls of 'std::set_difference' and one call of 'std::set_intersection'.
I think this is probably a reasonably efficient implementation:
Features:
a) operates in linear time.
b) works with all ordered container types for input and all iterator types for output.
c) only requires operator< to be defined on the contained type, as per stl algorithms on sorted ranges.
template<class I1, class I2, class I3, class I4, class ITarget1, class ITarget2, class ITarget3>
auto comm(I1 lfirst, I2 llast, I3 rfirst, I4 rlast, ITarget1 lonly, ITarget2 both, ITarget3 ronly)
{
while (lfirst != llast and rfirst != rlast)
{
auto&& l = *lfirst;
auto&& r = *rfirst;
if (l < r) *lonly++ = *lfirst++;
else if (r < l) *ronly++ = *rfirst++;
else *both++ = (++lfirst, *rfirst++);
}
while (lfirst != llast)
*lonly++ = *lfirst++;
while (rfirst != rlast)
*ronly++ = *rfirst++;
}
example:
#include <tuple>
#include <set>
#include <vector>
#include <unordered_set>
#include <iterator>
#include <iostream>
/// #pre l and r are ordered
template<class I1, class I2, class I3, class I4, class ITarget1, class ITarget2, class ITarget3>
auto comm(I1 lfirst, I2 llast, I3 rfirst, I4 rlast, ITarget1 lonly, ITarget2 both, ITarget3 ronly)
{
while (lfirst != llast and rfirst != rlast)
{
auto&& l = *lfirst;
auto&& r = *rfirst;
if (l < r) *lonly++ = *lfirst++;
else if (r < l) *ronly++ = *rfirst++;
else *both++ = (++lfirst, *rfirst++);
}
while (lfirst != llast)
*lonly++ = *lfirst++;
while (rfirst != rlast)
*ronly++ = *rfirst++;
}
int main()
{
//For example we have two sets on input
std::set<int>a = { 1, 2, 3, 4, 5 };
std::set<int>b = { 3, 4, 5, 6, 7 };
std::vector<int> left;
std::set<int> right;
std::unordered_set<int> both;
comm(begin(a), end(a),
begin(b), end(b),
back_inserter(left),
inserter(both, both.end()),
inserter(right, right.end()));
//So as result we need obtain 3 sets
//x1 = {1, 2} // present in a, but absent in b (difference)
//x2 = {3, 4, 5} // present on both sets (intersection)
//x3 = {6, 7} // present in b, but absent in a
std::copy(begin(left), end(left), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
std::copy(begin(both), end(both), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
std::copy(begin(right), end(right), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
}
example output (note that the 'both' target is an unordered set):
1, 2,
5, 3, 4,
6, 7,
There is no single function to do that, you'd have to call the three functions you mentioned, or write something yourself. That being said, here's my attempt, though I'm not sure it's going to be any faster than the three step method you've already described
#include <algorithm>
#include <iostream>
#include <iterator>
#include <set>
template <typename T>
void partition_sets(std::set<T> const& a,
std::set<T> const& b,
std::set<T>& difference_a,
std::set<T>& difference_b,
std::set<T>& intersection)
{
std::set_intersection(begin(a), end(a),
begin(b), end(b),
std::inserter(intersection, intersection.begin()));
std::copy_if(begin(a), end(a), std::inserter(difference_a, difference_a.begin()), [&intersection](int i)
{
return intersection.find(i) == intersection.end();
});
std::copy_if(begin(b), end(b), std::inserter(difference_b, difference_b.begin()), [&intersection](int i)
{
return intersection.find(i) == intersection.end();
});
}
Running your example
int main()
{
//For example we have two sets on input
std::set<int> a = { 1, 2, 3, 4, 5 };
std::set<int> b = { 3, 4, 5, 6, 7 };
std::set<int> x1;
std::set<int> x2;
std::set<int> x3;
partition_sets(a, b, x1, x2, x3);
std::cout << "a - b\n\t";
for (int i : x1)
{
std::cout << i << " ";
}
std::cout << "\n";
std::cout << "b - a\n\t";
for (int i : x2)
{
std::cout << i << " ";
}
std::cout << "\n";
std::cout << "intersection\n\t";
for (int i : x3)
{
std::cout << i << " ";
}
}
produces the output
a - b
1 2
b - a
6 7
intersection
3 4 5
Just write a wrapper for the three calls of the algorithms.
For example
#include <iostream>
#include<tuple>
#include <set>
#include <iterator>
#include <algorithm>
template <class T>
auto comm(const std::set<T> &first, const std::set<T> &second)
{
std::tuple<std::set<T>, std::set<T>, std::set<T>> t;
std::set_difference(first.begin(), first.end(),
second.begin(), second.end(),
std::inserter(std::get<0>(t), std::get<0>(t).begin()));
std::set_intersection(first.begin(), first.end(),
second.begin(), second.end(),
std::inserter(std::get<1>(t), std::get<1>(t).begin()));
std::set_difference(second.begin(), second.end(),
first.begin(), first.end(),
std::inserter(std::get<2>(t), std::get<2>(t).begin()));
return t;
}
int main()
{
std::set<int> a = { 1, 2, 3, 4, 5 };
std::set<int> b = { 3, 4, 5, 6, 7 };
auto t = comm(a, b);
for (auto x : std::get<0>(t)) std::cout << x << ' ';
std::cout << std::endl;
for (auto x : std::get<1>(t)) std::cout << x << ' ';
std::cout << std::endl;
for (auto x : std::get<2>(t)) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The program output is
1 2
3 4 5
6 7
I was wondering if there was a standard function that returns the minimum/maximum of the return values for a given range of elements. Something like this:
std::vector<int> list = { -2, -1, 6, 8, 10 };
auto it =
std::find_min_return_value(list.begin(), list.end(), std::abs, std::less<int>);
// it should be the iterator for -1
If there is no such, what is the best approach for a problem like this?
My list is long, I really don't want to copy it, and also don't want to call the function whose minimum return value I look for more than once per element. Thanks!
UPDATE:
Based on ForEveR's suggestion to use std::min_element, I made the following benchmarking tests:
std::vector<double> list = { -2, -1, 6, 8, 10 };
auto semi_expensive_test_function = [] (const double& a) { return asin(sin(a)); };
for(int i = 0; i < 10000000; ++i)
{
auto it = std::min_element(list.begin(), list.end(),
[&] (const double& a, const double& b) mutable
{
return(semi_expensive_test_function(a) < semi_expensive_test_function(b));
});
}
This worked just fine:
./a.out 11.52s user 0.00s system 99% cpu 11.521 total
After modifying the code to use a stateful lambda instead:
for(int i = 0; i < 10000000; ++i)
{
auto it = std::min_element(list.begin() + 1, list.end(),
[&, current_min_value = semi_expensive_test_function(*(list.begin()))] (const double& a, const double& b) mutable
{
double current_value = semi_expensive_test_function(b);
if(current_value < current_min_value)
{
current_min_value = std::move(current_value);
return true;
}
return false;
});
}
This resulted:
./a.out 6.34s user 0.00s system 99% cpu 6.337 total
Using stateful lambdas seems to be the way to go. The question is: is there a more code-compact way to achieve this?
With range-v3, it would be something like:
ranges::min(list, std::less<>{}, [](auto e) { return std::abs(e); });
Well, assuming Boost is like the standard library nowadays, you might use this:
#include <boost/range/adaptor/transformed.hpp>
#include <algorithm>
int main()
{
std::vector<int> list = { -2, -1, 6, 8, 10 };
auto abs_list = list | boost::adaptors::transformed(+[](int v) { return std::abs(v); });
// ^ - read http://stackoverflow.com/questions/11872558/using-boost-adaptors-with-c11-lambdas
auto it = std::min_element(abs_list.begin(), abs_list.end(), std::less<int>{});
std::cout << *it;
}
If it'll get reused, and to give you another option, you could write your own generic algorithm following std conventions.
template <typename T, typename ForwardIt, typename UnaryFunction, typename Comparator>
ForwardIt find_min_return_value(ForwardIt first, ForwardIt last, UnaryFunction op, Comparator compare)
{
if (first == last)
return last;
ForwardIt smallestItr = first;
T smallestValue = op(*first);
for (auto itr = first + 1; itr != last; ++itr)
{
T current = op(*itr);
if (compare(current, smallestValue))
{
smallestValue = current;
smallestItr = itr;
}
}
return smallestItr;
}
Usage is then quite code-compact, and the operation will only be performed once per element:
int main()
{
std::vector<int> list = { -2, -1, 6, 8, 10 };
auto it1 = find_min_return_value<int>(list.begin(), list.end(), [](int i){ return std::abs(i); }, std::less<int>());
std::vector<std::string> strings = { "Lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit" };
auto it3 = find_min_return_value<size_t>(strings.begin(), strings.end(), [](std::string s){ return s.length(); }, std::less<size_t>());
std::cout << *it1 << "\n"; // outputs -1
std::cout << *it3 << "\n"; // outputs sit
}
If you only suspect it may get reused one day it probably won't, and it's then overly complicated, and should then be just a simple function.
Lets say I have a vector<int> { 1, 1, 2, 3, 3, 3, 1, 1 } and I'd like to convert this into a vector<std::pair<int, int>> { {1, 2}, {2, 1}, {3, 3}, {1, 2} } of 'adjacent element counts':
I'd probably iterate over the vector with a flag indicating the start of a new 'adjacency set' and a counter which counts the number of consecutive elements. I was just wondering if there isn't already a more abstract and elegant solution in the STL as this seems like a very common use-case. Algorithms like unique, adjacent_find or equal_range seem pretty close to what I'm looking for but just not quite the right thing and probably no gain to implementing it from scratch myself.
From an algorithmic point of view the closest thing is run-length encoding I would say. I don't think there is a ready made algorithm to do that, but the code should be trivial:
std::vector<std::pair<int, int>> out;
for (int i: in)
{
if (out.empty() || out.back().first != i)
{
out.emplace_back(i, 1);
}
else
{
++out.back().second;
}
}
Live-example.
Eric Niebler's range library, which, AFAIU is in the process of becoming part of the standard library, has a group_by which is very similar to Python's itertools.groupby, and groups consecutive equivalent elements, just as you need.
To group your vector, you'd start with
const vector<int> l{ 1, 1, 2, 3, 3, 3, 1, 1 };
auto x = l | view::group_by(std::equal_to<int>());
which means that x is a view where adjacent integers belong to a group, if the integers are equal.
Now to iterate, and say, print each consecutive group and its size, you could do the following (I'm sure you can do it better than the following, but this is the limit of my use of this library):
for (auto i = x.begin();i != x.end(); ++i)
cout << *((*i).begin()) << " " << to_vector(*i).size() << endl;
Example
#include <vector>
#include <iostream>
#include <range/v3/all.hpp>
int main(int argc, char **argv) {
const std::vector<int> l{ 1, 1, 2, 3, 3, 3, 1, 1 };
auto x = l | ranges::view::group_by(std::equal_to<int>());
for (auto i = x.begin();i != x.end(); ++i)
std::cout << *((*i).begin()) << " " << ranges::to_vector(*i).size() << std::endl;
}
This prints out
$ ./a.out
1 2
2 1
3 3
1 2
As far as I know there is no such C++ library that will automatically do what you are asking.
Anyway, it is very simple to implement this though. Here is one way:
#include <iostream>
#include <vector>
using namespace std;
void count_equal_elements(vector<int>& vec, vector<pair<int,int> >& result){
if (vec.empty())
return;
int curr = vec[0];
int count = 1;
for (vector<int>::iterator it = vec.begin()+1; it != vec.end(); ++it){
if (curr == *it){
count++;
}
else{
result.push_back(make_pair(curr,count));
curr = *it;
count = 1;
}
}
result.push_back(make_pair(curr,count));
}
See it in ideone.
With std, you may do:
template <typename T>
std::vector<std::pair<T, std::size_t>>
adjacent_count(const std::vector<T>& v)
{
std::vector<std::pair<T, std::size_t>> res;
for (auto it = v.begin(), e = v.end(); it != e; /*Empty*/) {
auto it2 = std::adjacent_find(it, e, std::not_equal_to<>{});
if (it2 != e) {
++it2;
}
res.emplace_back(*it, std::distance(it, it2));
it = it2;
}
return res;
}
Demo
or
template <typename T>
std::vector<std::pair<T, std::size_t>>
adjacent_count(const std::vector<T>& v)
{
std::vector<std::pair<T, std::size_t>> res;
for (auto it = v.begin(), e = v.end(); it != e; /*Empty*/) {
const auto it2 = std::find_if(it, e, [&](const auto&x) { return x != *it; });
res.emplace_back(*it, std::distance(it, it2));
it = it2;
}
return res;
}
Demo
I have a problem that concerns determining if two vectors contain two elements the same. The elements may be anywhere in the vector, but they must be adjacent.
EDITED FOR MORE EXAMPLES
For example the following two vectors, when compared, would return false.
Vector 1 = [ 0, 1, 2, 3, 4, 6 ]
Vector 2 = [ 1, 4, 2, 0, 5, 3 ]
But the following two would return true:
Vector 1 = [ 0, 1, 2, 3, 4, 5 ]
Vector 2 = [ 4, 2, 1, 5, 0, 3 ]
because the 1,2 in the first vector would correspond to the 2,1 in the second vector.
True:
Vector 1 = [ 0, 1, 2, 3, 4, 5 ]
Vector 2 = [ 1, 4, 2, 0, 5, 3 ]
{5,0} is a pair, despite looping around the vector (I originally said this was false, thanks for spotting that 'Vlad from Moscow').
True:
Vector 1 = [ 0, 1, 2, 3, 4, 5 ]
Vector 2 = [ 4, 8, 6, 2, 1, 5, 0, 3 ]
{2,1} is still a pair, even though they are not in the same position
The actual application is that I have a polygon (face) with N points stored in a vector. To determine if a set of polygons completely enclose a 3D volume, I test each face to ensure that each edge is shared by another face (where an edge is defined by two adjacent points).
Thus, Face contains a vector of pointers to Points...
std::vector<Point*> points_;
and to check if a Face is surrounded, Face contains a member function...
bool isSurrounded(std::vector<Face*> * neighbours)
{
int count = 0;
for(auto&& i : *neighbours) // for each potential face
if (i != this) // that is not this face
for (int j = 0; j < nPoints(); j++) // and for each point in this face
for (int k = 0; k < i->nPoints(); k++ ) // check if the neighbour has a shared point, and that the next point (backwards or forwards) is also shared
if ( ( this->at(j) == i->at(k) ) // Points are the same, check the next and previous point too to make a pair
&& ( ( this->at((j+1)%nPoints()) == i->at((k+1)%(i->nPoints())) )
|| ( this->at((j+1)%nPoints()) == i->at((k+i->nPoints()-1)%(i->nPoints())) )))
{ count++; }
if (count > nPoints() - 1) // number of egdes = nPoints -1
return true;
else
return false;
}
Now, obviously this code is horrible. If I come back to this in 2 weeks, I probably won't understand it. So faced with the original problem, how would you neatly check the two vectors?
Note that if you are trying to decipher the provided code. at(int) returns the Point in a face and nPoints() returns the number of points in a face.
Many thanks.
Here is way if your element are same set of elements then assign index for each. (Didnt mention corner cases in pseudo ) :-
for(int i=0;i<vect1.size;i++) {
adj[vect1[i]][0] = vect1[i-1];
adj[vect2[i]][1] = vect2[i+1];
}
for(int j=0;j<vect2.size();j++) {
if(arr[vect2[i]][0]==(vect2[j-1] or vect[j+1]))
return true
if(arr[vect2[i]][1]==(vect2[j-1] or vect[j+1]))
return true
}
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
class AdjacentSort
{
public:
AdjacentSort(const vector<int>& ref);
~AdjacentSort();
bool operator()(int e1,int e2) const;
private:
const vector<int>& ref_;
};
AdjacentSort::AdjacentSort(const vector<int>& ref):
ref_(ref)
{
}
bool AdjacentSort::operator()(int e1, int e2) const
{
auto it1 = find(ref_.begin(),ref_.end(),e1);
auto it2 = find(ref_.begin(),ref_.end(),e2);
return distance(it1,it2) == 1;
}
AdjacentSort::~AdjacentSort()
{
}
int main()
{
vector<int> vec {1,2,3,4,5};
vector<int> vec2 {1,3,5,4,2};
AdjacentSort func(vec);
auto it = adjacent_find(vec2.begin(),vec2.end(),func);
cout << *it << endl;
return 0;
}
It returns the first element where two adjacent numbers are found, else it returns the end iterator.
Not efficient but following is a possibility.
bool comparePair ( pair<int,int> p1, pair<int,int> p2 ) {
return ( p1.first == p2.first && p1.second == p2.second )
|| ( p1.second == p2.first && p1.first == p2.second );
}
//....
vector< pair<int,int> > s1;
vector< pair<int,int> > s1;
vector< pair<int,int> > intersect( vec1.size() + vec2.size() );
for ( int i = 0; i < vec1.size()-1; i++ ) {
pair<int, int> newPair;
newPair.first = vec1[i];
newPair.first = vec1[i+1];
s1.push_back( newPair );
}
for ( int i = 0; i < vec2.size()-1; i++ ) {
pair<int, int> newPair;
newPair.first = vec2[i];
newPair.first = vec2[i+1];
s2.push_back( newPair );
}
auto it = std::set_intersection ( s1.begin(), s1.end(), s2.begin(), s2.end(),
intersect.begin(), comparePair );
return ( it != intersect.begin() ); // not sure about this.
If I have understood correctly these two vectors
std::vector<int> v1 = { 0, 1, 2, 3, 4, 5 };
std::vector<int> v2 = { 3, 5, 2, 1, 4, 0 };
contain adjacent equal elements. They are pair {1, 2 } in the first vector and pair { 2, 1 } in the second vector though positions of the pairs are different in the vectors.
In fact you already named the appropriate standard algorithm that can be used in this task. It is std::adjacent_find. For example
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> v1 = { 0, 1, 2, 3, 4, 5 };
std::vector<int> v2 = { 3, 5, 2, 1, 4, 0 };
bool result =
std::adjacent_find( v1.begin(), v1.end(),
[&v2]( int x1, int y1 )
{
return std::adjacent_find( v2.begin(), v2.end(),
[=]( int x2, int y2 )
{
return ( x1 == x2 && y1 == y2 || x1 == y2 && y1 == x2 );
} ) != v2.end();
} ) != v1.end();
std::cout << "result = " << std::boolalpha << result << std::endl;
return 0;
}
Here's my attempt at this problem. Quite simply, iterate through a, find the same element in b and then compare the next element in a with the elements before and after our position in b.
If it's a little wordier than it needed to be it was so that this function can be called with any containers. The only requirement is that the containers' iterators have to bidirectional.
#include <vector>
#include <iostream>
#include <algorithm>
#include <list>
using namespace std;
template <class Iter>
pair<Iter, Iter> get_neighbors(Iter begin, Iter current, Iter end)
{
auto p = make_pair(end, next(current));
if(current != begin)
p.first = prev(current);
return p;
}
template <class Iter1, class Iter2>
bool compare_if_valid(Iter1 p1, Iter1 end1, Iter2 p2)
{
return p1 != end1 && *p1 == *p2;
}
template <class C1, class C2>
auto neighbors_match(const C1 & a, const C2 & b) ->
decltype(make_pair(begin(a), begin(b)))
{
for(auto i = begin(a); i != end(a) && next(i) != end(a); ++i)
{
auto pos_in_b = find(begin(b), end(b), *i);
if(pos_in_b != end(b))
{
auto b_neighbors = get_neighbors(begin(b), pos_in_b, end(b));
if(compare_if_valid(b_neighbors.first, end(b), next(i)))
return {i, b_neighbors.first};
else if(compare_if_valid(b_neighbors.second, end(b), next(i)))
return {i, pos_in_b};
}
}
return {end(a), end(b)};
}
int main()
{
vector<int> a = {0, 1, 2, 3, 4, 5};
vector<int> b = {1, 4, 2, 0, 5, 3};
cout << boolalpha << (neighbors_match(a, b).first != a.end()) << endl;
vector<int> a2 = {0, 1, 2, 3, 4, 5};
list<int> b2 = {4, 2, 1, 5, 0, 3};
auto match = neighbors_match(a2, b2);
cout << boolalpha << distance(a2.cbegin(), match.first)
<< ' ' << distance(b2.cbegin(), match.second) << endl;
return 0;
}
First, write a make_paired_range_view which takes a range and returns a range whose iterators return std::tie( *it, *std::next(it) ). boost can help here, as their iterator writing code makes this far less annoying.
Next, unordered_equal takes two pairs and compares them ignoring order (so they are equal if the first both equal and the second both equal, or if the first equals the other second and vice versa).
Now we look for each of the left hand side's pairs in the right hand side using unordered_equal.
This has the advantage of taking 0 extra memory, but the disadvantage of O(n^2) time.
If we care more about time than memory, we can instead shove the pairs above into an unordered_set after sorting the pair to be in a canonical order. We then to through the second container, testing each pair (after sorting) to see if it is in the unordered_set. This takes O(n) extra memory, but runs in O(n) time. It can also be done without fancy dancy vector and range writing.
If the elements are more expensive than int, you can write a custom pseudo_pair that holds pointers and whose hash and equality is based on the content of the pointers.
An interesting "how would you do it..." problem... :-) It got me to take a 15 minute break from slapping edit boxes and combo boxes on forms and do a bit of programming for a change... LOL
So, here's how I think I'd do it...
First I'd define a concept of an edge as a pair of values (pair of ints - following your original example). I realize your example is just a simplification and you're actually using vectors of your own classes (Point* rather than int?) but it should be trivial to template-ize this code and use any type you want...
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <set>
#include <vector>
using namespace std;
typedef pair<int, int> edge;
Then I would create a set class that will keep its elements (edges) ordered in the way we need (by comparing edges in the order insensitive manner - i.e. if e1.first==e2.first and e1.second==e2.second then edges e1 and e2 are the same, but they are also same if e1.first==e2.second and e1.second==e2.first). For this, we could create a functional:
struct order_insensitive_pair_less
{
bool operator() (const edge& e1, const edge& e2) const
{
if(min(e1.first,e1.second)<min(e2.first,e2.second)) return true;
else if(min(e1.first,e1.second)>min(e2.first,e2.second)) return false;
else return(max(e1.first,e1.second)<max(e2.first,e2.second));
}
};
Finally, our helper class (call it edge_set) would be a simple derivative of a set ordered using the above functional with a couple of convenience methods added - a constructor that populates the set from a vector (or your Face class in practice) and a tester function (bool shares_edge(const vector&v)) that tells us whether or not the set shares an edge with another. So:
struct edge_set : public set<edge, order_insensitive_pair_less>
{
edge_set(const vector<int>&v);
bool shares_edge(const vector<int>&v);
};
Implemented as:
edge_set::edge_set(const std::vector<int>&v) : set<edge, order_insensitive_pair_less>()
{
if(v.size()<2) return; // assume there must be at least 2 elements in the vector since it is supposed to be a list of edges...
for (std::vector<int>::const_iterator it = v.begin()+1; it != v.end(); it++)
insert(edge(*(it-1), *it));
}
bool edge_set::shares_edge(const std::vector<int>& v)
{
edge_set es(v);
for(iterator es_it = begin(); es_it != end(); es_it++)
if(es.count(*es_it))
return true;
return false;
}
The usage then becomes trivial (and reasonably elegant). Assuming you have the two vectors you gave as examples in the abstract of your problem in variables v1 and v2, to test whether they share an edge you would just write:
if(edge_set(v1).shares_edge(v2))
// Yup, they share an edge, do something about it...
else
// Nope, not these two... Do something different...
The only assumption about the number of elements in this approach is that each vector will have at least 2 (since you cannot have an "edge" without at least to vertices). However, even if this is not the case (one of the vectors is empty or has just one element) - this will result in an empty edge_set so you'll just get an answer that they have no shared edges (since one of the sets is empty). No big deal... In my opinion, doing it this way would certainly pass the "two week test" since you would have a dedicated class where you could have a couple of comment lines to say what it's doing and the actual comparison is pretty readable (edge_set(v1).shares_edge(v2))...
If I understand your question:
std::vector<int> a, b;
std::vector<int>::iterator itB = b.begin();
std::vector<int>::iterator itA;
std::vector<std::vector<int>::iterator> nears;
std::vector<int>::iterator near;
for(;itB!=b.end() ; ++itB) {
itA = std::find(a.begin(), a.end(), *itB);
if(nears.empty()) {
nears.push_back(itA);
} else {
/* there's already one it, check the second */
if(*(++nears[0])==*itA && itA != a.end() {
nears.push_back(itA);
} else {
nears.clear();
itB--;
}
}
if(nears.size() == 2) {
return true;
}
}
return false;
I think this is the most concise i can come up with.
bool check_for_pairs(std::vector<int> A, std::vector<int> B) {
auto lastA = A.back();
for (auto a : A) {
auto lastB = B.back();
for (auto b : B) {
if ((b == a && lastB == lastA) || (b == lastA && lastB == a)) return true;
lastB = b;
}
lastA = a;
}
return false;
}
Are more time efficient approach would be to use a set
bool check_for_pairs2(std::vector<int> A, std::vector<int> B) {
using pair = std::pair<int,int>;
std::unordered_set< pair, boost::hash<pair> > lookup;
auto last = A.back();
for (auto a : A) {
lookup.insert(a < last ? std::make_pair(a,last) : std::make_pair(last,a));
last = a;
}
last = B.back();
for (auto b : B) {
if (lookup.count(b < last ? std::make_pair(b,last) : std::make_pair(last,b)))
return true;
last = b;
}
return false;
}
If you implement a hash function that hashes (a,b) and (b,a) to the same, you could remove the check for which value is smallest
What you are essentially asking for is whether the edge sets of two faces (let's call them a and b) are disjoint or not. This can be decomposed into the problem of whether any of the edges in b are in a, which is just a membership test. The issue then, is that vectors are not great at membership tests.
My solution, is to convert one of the vectors into an unordered_set< pair<int, int> >.
an unordered_set is just a hash table, and the pairs represent the edges.
In representing edges, I've gone for a normalising scheme where the indices of the vertices are in increasing order (so [2,1] and [1,2] both get stored as [1,2] in my edge set). This makes equality testing that little bit easier (in that it is just the equality of the pair)
So here is my solution:
#include <iostream>
#include <utility>
#include <functional>
#include <vector>
#include <unordered_set>
using namespace std;
using uint = unsigned int;
using pii = pair<int,int>;
// Simple hashing for pairs of integers
struct pii_hash {
inline size_t
operator()(const pii & p) const
{
return p.first ^ p.second;
}
};
// Order pairs of integers so the smallest number is first
pii ord_pii(int x, int y) { return x < y ? pii(x, y) : pii(y, x); }
bool
shares_edge(vector<int> a, vector<int> b)
{
unordered_set<pii, pii_hash> edge_set {};
// Create unordered set of pairs (the Edge Set)
for(uint i = 0; i < a.size() - 1; ++i)
edge_set.emplace( ord_pii(a[i], a[i+1]) );
// Check if any edges in B are in the Edge Set of A
for(uint i = 0; i < b.size() - i; ++i)
{
pii edge( ord_pii(b[i], b[i+1]) );
if( edge_set.find(edge) != edge_set.end() )
return true;
}
return false;
}
int main() {
vector<int>
a {0, 1, 2, 3, 4, 5},
b {1, 4, 2, 0, 5, 3},
c {4, 2, 1, 0, 5, 3};
shares_edge(a, b); // false
shares_edge(a, c); // true
return 0;
}
In your particular case, you may want to make shares_edge a member function of your Face class. It may also be beneficial to precompute the edge set and store it as an instance variable of Face as well, but that depends on how often the edge data changes vs how often this calculation occurs.
EDIT Extra Solution
EDIT 2 Fixed for question change: edge set now wraps around point list.
Here's what it would look like if you added the edge set, precomputed at initialisation to some sort of Face class. The private nested Edge class can be thought of as decorating your current representation of an edge (i.e. two adjacent positions in the point list), with an actual class, so that collections like sets can treat the index into the point list as an actual edge:
#include <cassert>
#include <iostream>
#include <utility>
#include <functional>
#include <vector>
#include <unordered_set>
using uint = unsigned int;
class Face {
struct Edge {
int _index;
const std::vector<int> *_vertList;
Edge(int index, const std::vector<int> *vertList)
: _index {index}
, _vertList {vertList}
{};
bool
operator==(const Edge & other) const
{
return
( elem() == other.elem() && next() == other.next() ) ||
( elem() == other.next() && next() == other.elem() );
}
struct hash {
inline size_t
operator()(const Edge & e) const
{
return e.elem() ^ e.next();
}
};
private:
inline int elem() const { return _vertList->at(_index); }
inline int
next() const
{
return _vertList->at( (_index + 1) % _vertList->size() );
}
};
std::vector<int> _vertList;
std::unordered_set<Edge, Edge::hash> _edgeSet;
public:
Face(std::initializer_list<int> verts)
: _vertList {verts}
, _edgeSet {}
{
for(uint i = 0; i < _vertList.size(); ++i)
_edgeSet.emplace( Edge(i, &_vertList) );
}
bool
shares_edge(const Face & that) const
{
for(const Edge & e : that._edgeSet)
if( _edgeSet.find(e) != _edgeSet.end() )
return true;
return false;
}
};
int main() {
Face
a {0, 1, 2, 3, 4, 5},
b {1, 4, 2, 0, 5, 3},
c {4, 2, 1, 0, 5, 3},
d {0, 1, 2, 3, 4, 6},
e {4, 8, 6, 2, 1, 5, 0, 3};
assert( !d.shares_edge(b) );
assert( a.shares_edge(b) );
assert( a.shares_edge(c) );
assert( a.shares_edge(e) );
return 0;
}
As you can see, this added abstraction makes for a quite pleasing implementation of shares_edge(), but that is because the real trick is in the definition of the Edge class (or to be more specific the relationship that e1 == e2 <=> Edge::hash(e1) == Edge::hash(e2)).
I know I'm a little late with this, but here's my take at it:
Not in-situ:
#include <algorithm>
#include <iostream>
#include <tuple>
#include <vector>
template<typename Pair>
class pair_generator {
public:
explicit pair_generator(std::vector<Pair>& cont)
: cont_(cont)
{ }
template<typename T>
bool operator()(T l, T r) {
cont_.emplace_back(r, l);
return true;
}
private:
std::vector<Pair>& cont_;
};
template<typename Pair>
struct position_independant_compare {
explicit position_independant_compare(const Pair& pair)
: pair_(pair)
{ }
bool operator()(const Pair & p) const {
return (p.first == pair_.first && p.second == pair_.second) || (p.first == pair_.second && p.second == pair_.first);
}
private:
const Pair& pair_;
};
template<typename T>
using pair_of = std::pair<T, T>;
template<typename T>
std::ostream & operator <<(std::ostream & stream, const pair_of<T>& pair) {
return stream << '[' << pair.first << ", " << pair.second << ']';
}
int main() {
std::vector<int>
v1 {0 ,1, 2, 3, 4, 5},
v2 {4, 8, 6, 2, 1, 5, 0, 3};
std::vector<pair_of<int> >
p1 { },
p2 { };
// generate our pairs
std::sort(v1.begin(), v1.end(), pair_generator<pair_of<int>>{ p1 });
std::sort(v2.begin(), v2.end(), pair_generator<pair_of<int>>{ p2 });
// account for the fact that the first and last element are a pair too
p1.emplace_back(p1.front().first, p1.back().second);
p2.emplace_back(p2.front().first, p2.back().second);
std::cout << "pairs for vector 1" << std::endl;
for(const auto & p : p1) { std::cout << p << std::endl; }
std::cout << std::endl << "pairs for vector 2" << std::endl;
for(const auto & p : p2) { std::cout << p << std::endl; }
std::cout << std::endl << "pairs shared between vector 1 and vector 2" << std::endl;
for(const auto & p : p1) {
const auto pos = std::find_if(p2.begin(), p2.end(), position_independant_compare<pair_of<int>>{ p });
if(pos != p2.end()) {
std::cout << p << std::endl;
}
}
}
Example output on ideone
In-situ:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <tuple>
#include <vector>
template<typename T>
struct in_situ_pair
: std::iterator<std::forward_iterator_tag, T> {
using pair = std::pair<T, T>;
in_situ_pair(std::vector<T>& cont, std::size_t idx)
: cont_(cont), index_{ idx }
{ }
pair operator*() const {
return { cont_[index_], cont_[(index_ + 1) % cont_.size()] };
}
in_situ_pair& operator++() {
++index_;
return *this;
}
bool operator==(const pair& r) const {
const pair l = operator*();
return (l.first == r.first && l.second == r.second)
|| (l.first == r.second && l.second == r.first);
}
bool operator==(const in_situ_pair& o) const {
return (index_ == o.index_);
}
bool operator!=(const in_situ_pair& o) const {
return !(*this == o);
}
public:
friend bool operator==(const pair& l, const in_situ_pair& r) {
return (r == l);
}
private:
std::vector<T>& cont_;
std::size_t index_;
};
template<typename T>
using pair_of = std::pair<T, T>;
template<typename T>
std::ostream & operator <<(std::ostream & stream, const pair_of<T>& pair) {
return stream << '[' << pair.first << ", " << pair.second << ']';
}
namespace in_situ {
template<typename T>
in_situ_pair<T> begin(std::vector<T>& cont) { return { cont, 0 }; }
template<typename T>
in_situ_pair<T> end(std::vector<T>& cont) { return { cont, cont.size() }; }
template<typename T>
in_situ_pair<T> at(std::vector<T>& cont, std::size_t i) { return { cont, i }; }
}
int main() {
std::vector<int>
v1 {0 ,1, 2, 3, 4, 5},
v2 {4, 8, 6, 2, 1, 5, 0, 3};
for(std::size_t i = 0; i < v1.size(); ++i) {
auto pos = std::find(in_situ::begin(v2), in_situ::end(v2), in_situ::at(v1, i));
if(pos != in_situ::end(v2)) {
std::cout << "common: " << *pos << std::endl;
}
}
}
Example output on ideone
There have been a lot of great answers, and I'm sure people searching for the general problem of looking for adjacent pairs of equal elements in two vectors will find them enlightening. I have decided to answer my own question because I think a neater version of my original attempt is the best answer for me.
Since there doesn't seem to be a combination of std algorithms that make the methodology simpler, I believe looping and querying each element to be the most concise and understandable.
Here is the algorithm for the general case:
std::vector<int> vec1 = { 1, 2, 3, 4, 5, 6 };
std::vector<int> vec2 = { 3, 1, 4, 2, 6, 5 };
// Loop over the elements in the first vector, looking for an equal element in the 2nd vector
for(int i = 0; i < vec1.size(); i++) for(int j = 0; j < vec2.size(); j++)
if ( vec1[i] == vec2[j] &&
// ... Found equal elements, now check if the next element matches the next or previous element in the other vector
( vec1[(i+1) % vec1.size()] == vec2[(j+1) % vec2.size()]
||vec1[(i+1) % vec1.size()] == vec2[(j-1+vec2.size()) % vec2.size()] ) )
return true;
return false;
Or in my specific case, where I am actually checking a vector of vectors, and where the elements are no longer ints, but pointers to a class.
(The operator[] of the Face class returns an element of a vector belonging to the face).
bool isSurrounded(std::vector<Face*> * neighbours)
{
// We can check if each edge aligns with an edge in a nearby face,
// ... if each edge aligns, then the face is surrounded
// ... an edge is defined by two adjacent points in the points_ vector
// ... so we check for two consecutive points to be equal...
int count = 0;
// for each potential face that is not this face
for(auto&& i : *neighbours) if (i != this)
// ... loop over both vectors looking for an equal point
for (int j = 0; j < nPoints(); j++) for (int k = 0; k < i->nPoints(); k++ )
if ( (*this)[j] == (*i)[k] &&
// ... equal points have been found, check if the next or previous points also match
( (*this)[(j+1) % nPoints()] == (*i)[(k+1) % i->nPoints()]
|| (*this)[(j+1) % nPoints()] == (*i)[(k-1+i->nPoints()) % i->nPoints()] ) )
// ... an edge is shared
{ count++; }
// number of egdes = nPoints -1
if (count > nPoints() - 1)
return true;
else
return false;
}