You can find pairs common to all vectors ( common_pairs ), and then remove pairs from each vector that do not belong to the intersection using set_intersection() :
#include <algorithm> // set_intersection #include <iostream> #include <iterator> // back_inserter #include <string> #include <type_traits> // remove_reference #include <utility> // pair #include <vector> int main() { using namespace std; typedef vector<pair<int, string>> V; V seqs[] = { {{1, "a"}, {2, "b"}, {3, "c"}}, {{1, "k"}, {5, "q"}, {4, "r"}}, {{1, "e"}, {6, "d"}, {7, "v"}}, }; // find intersection of k vectors V common_pairs; auto less_first = [](auto a, auto b) { return a.first < b.first; }; set_intersectionk(begin(seqs), end(seqs), back_inserter(common_pairs), less_first); // remove pairs that are not in the intersection for (auto&& v : seqs) { V temp; set_intersection(begin(v), end(v), begin(common_pairs), end(common_pairs), back_inserter(temp), less_first); v.swap(temp); } // print results for (auto&& v : seqs) { for (auto&& p : v) cout << "(" << p.first << ", " << p.second << ") "; cout << endl; } }
Example:
$ g++ -std=c++14 *.cc && ./a.out (1, a) (1, k) (1, e)
Where set_intersectionk() simply finds in pairs the intersection of vectors:
/// Find common elements among collections given in [first, last) range. template<class InputIt, class OutIt, class Compare> OutIt set_intersectionk(InputIt first, InputIt last, OutIt out, Compare comp) { if (first == last) // no collections return out; typedef std::vector<std::remove_reference_t<decltype(*begin(*first))>> V; V intersection(begin(*first), end(*first)); for (++first; first != last; ++first) { V temp; temp.swap(intersection); std::set_intersection(std::begin(*first), std::end(*first), std::begin(temp), std::end(temp), std::back_inserter(intersection), comp); } return std::copy(begin(intersection), end(intersection), out); }
Input collections are not required to be vectors. In terms of the worst case ( k identical collections), the time complexity of the algorithm is already optimal O(k*n) . If the intersection is noticeably smaller, then you can improve the execution time, if you do not look at each (different) element, for example, using the doubling search suggested in the discussion of a similar issue for the implementation of set_intersection() :
/// Return the first iterator such that !comp(*it, key) template<class It, class K = typename std::iterator_traits<It>::value_type, class Compare = std::less<K> > It doubling_lower_bound(It first, It last, K key, Compare comp = {}) { typename std::iterator_traits<It>::difference_type upper_bound = 1, count = std::distance(first, last); while (upper_bound < count && comp(*std::next(first, upper_bound), key)) upper_bound *= 2; return std::lower_bound(std::next(first, upper_bound / 2), std::next(first, std::min(upper_bound, count)), key, comp); } template<class It1, class It2, class OutIt, class Compare> OutIt set_intersection(It1 first1, It1 last1, It2 first2, It2 last2, OutIt out, Compare comp) { for ( ; first2 != last2; ++first2) { first1 = doubling_lower_bound(first1, last1, *first2, comp); if (first1 == last1) break; // all(first1s) < *first2 <= all(first2s) first2 = doubling_lower_bound(first2, last2, *first1, comp); if (first2 == last2) break; // all(first2s) < *first1 <= all(first1s) *out++ = *first1++; // !(a < b) && !(b < a) <=> a == b } return out; }
(1,z)? Leave or delete? And if in the second -(2,q)- or only those that are in all three are needed? - Harry