Symmetric difference of many sets - c++

The symmetric difference of sets is the set of all elements that do not belong to all the sets. If the sets are already sorted, then I've come up with the solution below that uses std::set_union, std::set_intersection, and std::set_difference. But I'm not convinced that it is the cleanest way to do it. Can someone think of a better (perhaps more efficient) way that uses one simple recursion with variadic template arguments to get the result right away? Perhaps using std::set_symmetric_difference recursively? I have trouble figuring that out. Here is my solution using the above method:
#include <iostream>
#include <vector>
#include <algorithm>
template <typename Container>
std::vector<typename Container::value_type> multi_union (const Container& container) {
return container;
}
template <typename Container1, typename Container2, typename... Containers>
std::vector<typename Container1::value_type> multi_union (const Container1& container1,
const Container2& container2, const Containers&... containers) {
std::vector<typename Container1::value_type> v;
std::set_union (container1.begin(), container1.end(), container2.begin(), container2.end(),
std::back_inserter(v));
return multi_union (v, containers...);
}
template <typename Container>
std::vector<typename Container::value_type> multi_intersection (const Container& container) {
return container;
}
template <typename Container1, typename Container2, typename... Containers>
std::vector<typename Container1::value_type> multi_intersection (const Container1& container1,
const Container2& container2, const Containers&... containers) {
std::vector<typename Container1::value_type> v;
std::set_intersection (container1.begin(), container1.end(), container2.begin(),
container2.end(), std::back_inserter(v));
return multi_intersection (v, containers...);
}
template <typename Container, typename... Containers>
std::vector<typename Container::value_type> multi_symmetric_difference (const Container&
container, const Containers&... containers) {
const std::vector<typename Container::value_type>
a = multi_union (container, containers...),
b = multi_intersection (container, containers...);
std::vector<typename Container::value_type> v;
std::set_difference (a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(v));
return v;
}
int main() {
std::vector<int> a = {3,4,6,1,2}, b = {6,8,9,2}, c = {6,7,4,5,2};
std::sort (a.begin(), a.end()); std::sort (b.begin(), b.end()); std::sort (c.begin(), c.end());
const std::vector<int> s = multi_symmetric_difference (a, b, c);
for (int x : s) std::cout << x << ' '; // 1 3 4 5 7 8 9
}
Also, like std::set_symmetric_difference, multi_symmetric_difference should output to an output iterator so that the resulting container can be of any type (not just vector).

Related

Deduce template type from lambda invocation on container

I have the following map implementation that takes a vector and a lambda as input and returns a new vector.
template <typename R, typename T, typename Predicate>
std::vector<R> map(const std::vector<T> &v, Predicate p) {
std::vector<R> mapd(v.size());
std::transform(v.begin(), v.end(), mapd.begin(), p);
return mapd;
}
Which I use in the following way
std::vector<int> input{1, 2, 3};
auto result = map<float>(input, [] (const int &v) { return v * 2.0; }); // result should be vector<float>{2., 4., 6.}
This works, but I want to see if I can deduce the R template type without specifying it in the call.
Now, I know that I have both the return type of the lambda and the type of the input vector, is there a way to do this? I've tried using std::result_of_t<p(t)> but got nowhere.
Do you mean something as follows ?
template <typename T, typename Predicate,
typename R = decltype(std::declval<Predicate>()(std::declval<T>()))>
std::vector<R> map(const std::vector<T> &v, Predicate p) {
std::vector<R> mapd(v.size());
std::transform(v.begin(), v.end(), mapd.begin(), p);
return mapd;
}
Or maybe (if you can use at least C++14)
template <typename T, typename Predicate>
auto map(const std::vector<T> &v, Predicate p) {
std::vector<decltype(p(v[0]))> mapd(v.size());
std::transform(v.begin(), v.end(), mapd.begin(), p);
return mapd;
}

Combine all elements from couple of vectors into one using templates

I am trying to combine couple of vectors into one using templates, but I can't make it work because of the compiler error:
error: no matching function for call to 'to_vec_from_vectors(std::vector<std::vector<std::__cxx11::basic_string<char> > >&)'
The code is pretty straightforward. I have two functions, one is iterating via array of vectors, another is adding all the elements to the result vector. Appreciate any help. I have the following code:
template <typename Container>
Container& concat(Container& c1, Container const& c2)
{
c1.insert(end(c1), begin(c2), end(c2));
return c1;
}
template <typename Container>
inline auto to_vec_from_vectors(Container& c) -> std::vector<typename decltype(*std::begin(c))::value_type>
{
std::vector<typename decltype(*std::begin(c))::value_type> v;
for (auto& e : c)
{
concat(v, e);
}
return v;
}
int main()
{
vector<string> malwares1 = {"Malware1", "Malware2"};
vector<string> malwares2 = {"Malware3", "Malware4"};
vector<vector<string>> mVector = {malwares1, malwares2};
vector<string> malwares3 = to_vec_from_vectors(mVector);
return 0;
}
The type typename decltype(*std::begin(c))::value_type seems to be what is giving you problems. typename Container::value_type::value_type works for me.
#include <vector>
#include <string>
template <typename Container>
Container& concat(Container& c1, Container const& c2)
{
c1.insert(end(c1), begin(c2), end(c2));
return c1;
}
template <typename Container>
inline auto to_vec_from_vectors(Container& c) -> std::vector<typename Container::value_type::value_type>
{
std::vector<typename Container::value_type::value_type> v;
for (auto& e : c)
{
concat(v, e);
}
return v;
}
int main()
{
using std::vector;
using std::string;
vector<string> malwares1 = {"Malware1", "Malware2"};
vector<string> malwares2 = {"Malware3", "Malware4"};
vector<vector<string>> mVector = {malwares1, malwares2};
vector<string> malwares3 = to_vec_from_vectors(mVector);
return 0;
}
*std::begin(c) returns vector<string>&, you cannot store reference to vector in another vector, use remove_reference_t to discard it:
template <typename Container>
inline
auto to_vec_from_vectors(Container& c) -> std::vector<typename std::remove_reference_t<decltype(*std::begin(c))>::value_type>
{
std::vector<typename std::remove_reference_t<decltype(*std::begin(c))>::value_type> v;
for (auto& e : c)
{
concat(v, e);
}
return v;
}

Negate a lambda without knowing the argument type?

I'm trying to write an in-place filter function that works similarly to Python's filter. For example:
std::vector<int> x = {1, 2, 3, 4, 5};
filter_ip(x, [](const int& i) { return i >= 3; });
// x is now {3, 4, 5}
First I tried this:
template <typename Container, typename Filter>
void filter_ip(Container& c, Filter&& f)
{
c.erase(std::remove_if(c.begin(), c.end(), std::not1(f)), c.end());
}
However, that doesn't work because lambdas don't have an argument_type field.
This following variant does work:
template <typename Container, typename Filter>
void filter_ip(Container& c, Filter&& f)
{
c.erase(std::remove_if(c.begin(), c.end(),
[&f](const typename Container::value_type& x) {
return !f(x);
}),
c.end());
}
However, it seems less than ideal because before, it would only have required that Container have begin, end, and erase, while now it also requires that it defines a value_type. Plus it looks a little unwieldy.
This is the 2nd approach in this answer. The first would use std::not1(std::function<bool(const typename Container::value_type&)>(f)) instead of the lambda, which still requires the type.
I also tried specifying the arg func as an std::function with a known argument type:
template <typename Container, typename Arg>
void filter_ip(Container& c, std::function<bool(const Arg&)>&& f)
{
c.erase(std::remove_if(c.begin(), c.end(), std::not1(f)), c.end());
}
But then I get:
'main()::<lambda(const int&)>' is not derived from 'std::function<bool(const Arg&)>'
Is there any way around this? Intuitively it seems it should be really simple since all you need to do is apply a not to a bool which you already know f returns.
If you can't use C++14 generic lambdas, how about delegating to a classic functor with a templated operator() :
#include <utility>
#include <vector>
#include <algorithm>
#include <iostream>
template <class F>
struct negate {
negate(F&& f)
: _f(std::forward<F>(f)) {}
template <class... Args>
bool operator () (Args &&... args) {
return !_f(std::forward<Args>(args)...);
}
private:
F _f;
};
template <typename Container, typename Filter>
void filter_ip(Container& c, Filter&& f)
{
c.erase(std::remove_if(
c.begin(),
c.end(),
negate<Filter>(std::forward<Filter>(f))),
c.end()
);
}
int main() {
std::vector<int> v {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
filter_ip(v, [](int i) {return bool(i%2);});
for(auto &&i : v)
std::cout << i << ' ';
std::cout << '\n';
}
Output :
1 3 5 7 9
Live on Coliru
template<class F>
struct not_f_t {
F f;
template<class...Ts>
decltype(!std::declval<typename std::result_of<F&(Ts...)>::type>())
operator()(Ts&&...ts) {
return !f(std::forward<Ts>(ts)...);
}
};
template<class F, class dF=typename std::decay<F>::type>
not_f_t<dF> not_f(F&& f){
return {std::forward<F>(f)};
}
or in C++14, we can dispense with the not_f_t class and do:
template<class F,class dF=std::decay_t<F>>// dF optional
auto not_f(F&& f){
return [f=std::forward<F>(f)](auto&&...args)mutable
->decltype(!std::declval<std::result_of_t<dF&(decltype(args)...)>>()) // optional, adds sfinae
{
return !f(decltype(args)(args)...);
};
}
and then, because it rocks:
template<class C, class F>
void erase_remove_if( C&& c, F&& f ) {
using std::begin; using std::end;
c.erase( std::remove_if( begin(c), end(c), std::forward<F>(f) ), end(c) );
}
we get:
std::vector<int> x = {1, 2, 3, 4, 5};
erase_remove_if(x, not_f([](int i){return i>=3;}));
It seems to me that if you already require a begin, end, and erase, also requiring a value_type is a pretty minor addition. If you could get away from requiring erase, that would gain you at least a few real containers, but eliminating a requirement for value_type doesn't accomplish much.
Nonetheless, in case you had a container that really did define erase, but not value_type, you could side-step the requirement for it to define value_type directly by getting the value_type from the iterator:
template <typename Container, typename Filter>
void filter_ip(Container& c, Filter&& f) {
using It = decltype(c.begin());
c.erase(std::remove_if(c.begin(), c.end(),
[&f](const std::iterator_traits<It>::value_type& x) {
return !f(x);
}),
c.end());
}
Using iterator_traits<T>::value_type, you can (for example) get the pointee type when the iterator is really a pointer. I don't know of any practical advantage in this case though when you already require begin(), end() and (especially) erase. We could eliminate the requirement for begin() and end() as members by using std::begin(c) and std::end(c), but (again) that doesn't really gain us anything meaningful (like the ability to work with arrays) when we still need an erase member.
An even simpler approach would be to use std::partition instead:
template <typename Container, typename Filter>
void filter_ip(Container& c, Filter&& f) {
c.erase(std::partition(c.begin(), c.end(), f), c.end());
}
This does have the disadvantage that it can (will) rearrange the elements that it keeps, so it won't work if you really need to retain the original order. This could also be less efficient if copy/move construction is much less expensive than swapping (but that's fairly uncommon).
One final possibility would be to just implement the algorithm on your own instead of delegating to another algorithm:
template <typename Container, typename Filter>
void filter2(Container& c, Filter&& f) {
auto dst = c.begin();
for (auto src = dst; src != c.end(); ++src)
if (f(*src)) {
*dst = *src;
++dst;
}
c.erase(dst, c.end());
}
If you prefer to avoid self-assignment, you could add:
while (f(*dst))
++dst;
...before the for loop above.

Search variable/item/attribute using STL in c++?

There is any way to search an item or attribute or variable in C++ using STL .
We can use any container of STL providing Searching time as less as possible . Container contains pair<int,int> . i would like to search a pair p(a,x) which should return all pairs X whose p.first == Xi.first and p.second != Xi.second for all i .
e.g.
Let container is unordered_set .
unordered_set< pair<int , int > > myset =
{{1,2},{1,5},{1,6},{2,4},{3,5},{4,6},{6,7},{6,8}};
if i search for p(1,5) then it should return pair(1,2),(1,6)
if i search for p(2,4) or (3,5),(6,7) then it should return NULL i.e. nothing
if i search for p(6,7) then it should return pair(6,8)
Something along the lines of
std::vector<std::pair<int, int>>
find_nonmatching_values(const std::unordered_multimap<int, int> & thing,
int key, int value) {
std::vector<std::pair<int, int>> ret;
auto range = thing.equal_range(key);
std::copy_if(range.first, range.second, std::back_inserter(ret),
[value](const std::pair<const int, int> &p)
{ return p.second != value; });
return ret;
}
Demo. Templatizing this code is left as an exercise for the reader.
Slightly more general than T.C.s version:
#include <type_traits>
#include <iterator>
template <typename T, typename InputIterator, typename OutputIterator, typename Comparator>
void find_mismatches(InputIterator first, InputIterator last,
T const& val, OutputIterator out, Comparator comp)
{
for (; first != last; ++first)
{
auto&& f = *first;
if (!comp(f.second, val))
*out++ = f;
}
}
template <typename AssociativeCont, typename OutputIterator, typename Comparator>
void find_mismatches(AssociativeCont&& rng, typename std::remove_reference<AssociativeCont>::type::value_type const& val, OutputIterator out, Comparator comp)
{
auto range = rng.equal_range(val.first);
find_mismatches(range.first, range.second, val.second, out, comp);
}
template <typename AssociativeCont, typename OutputIterator>
void find_mismatches(AssociativeCont&& rng, typename std::remove_reference<AssociativeCont>::type::value_type const& val, OutputIterator out)
{
auto range = rng.equal_range(val.first);
find_mismatches(range.first, range.second, val.second, out, std::equal_to<decltype(val.second)>());
}
Demo. Note that you could still expand this by using a template parameter that is a pointer-to-member to a value_type's member.

Appending a vector to a vector [duplicate]

This question already has answers here:
Concatenating two std::vectors
(27 answers)
Closed 7 years ago.
Assuming I have 2 standard vectors:
vector<int> a;
vector<int> b;
Let's also say the both have around 30 elements.
How do I add the vector b to the end of vector a?
The dirty way would be iterating through b and adding each element via vector<int>::push_back(), though I wouldn't like to do that!
a.insert(a.end(), b.begin(), b.end());
or
a.insert(std::end(a), std::begin(b), std::end(b));
The second variant is a more generically applicable solution, as b could also be an array. However, it requires C++11. If you want to work with user-defined types, use ADL:
using std::begin, std::end;
a.insert(end(a), begin(b), end(b));
std::copy (b.begin(), b.end(), std::back_inserter(a));
This can be used in case the items in vector a have no assignment operator (e.g. const member).
In all other cases this solution is ineffiecent compared to the above insert solution.
While saying "the compiler can reserve", why rely on it? And what about automatic detection of move semantics? And what about all that repeating of the container name with the begins and ends?
Wouldn't you want something, you know, simpler?
(Scroll down to main for the punchline)
#include <type_traits>
#include <vector>
#include <iterator>
#include <iostream>
template<typename C,typename=void> struct can_reserve: std::false_type {};
template<typename T, typename A>
struct can_reserve<std::vector<T,A>,void>:
std::true_type
{};
template<int n> struct secret_enum { enum class type {}; };
template<int n>
using SecretEnum = typename secret_enum<n>::type;
template<bool b, int override_num=1>
using EnableFuncIf = typename std::enable_if< b, SecretEnum<override_num> >::type;
template<bool b, int override_num=1>
using DisableFuncIf = EnableFuncIf< !b, -override_num >;
template<typename C, EnableFuncIf< can_reserve<C>::value >... >
void try_reserve( C& c, std::size_t n ) {
c.reserve(n);
}
template<typename C, DisableFuncIf< can_reserve<C>::value >... >
void try_reserve( C& c, std::size_t ) { } // do nothing
template<typename C,typename=void>
struct has_size_method:std::false_type {};
template<typename C>
struct has_size_method<C, typename std::enable_if<std::is_same<
decltype( std::declval<C>().size() ),
decltype( std::declval<C>().size() )
>::value>::type>:std::true_type {};
namespace adl_aux {
using std::begin; using std::end;
template<typename C>
auto adl_begin(C&&c)->decltype( begin(std::forward<C>(c)) );
template<typename C>
auto adl_end(C&&c)->decltype( end(std::forward<C>(c)) );
}
template<typename C>
struct iterable_traits {
typedef decltype( adl_aux::adl_begin(std::declval<C&>()) ) iterator;
typedef decltype( adl_aux::adl_begin(std::declval<C const&>()) ) const_iterator;
};
template<typename C> using Iterator = typename iterable_traits<C>::iterator;
template<typename C> using ConstIterator = typename iterable_traits<C>::const_iterator;
template<typename I> using IteratorCategory = typename std::iterator_traits<I>::iterator_category;
template<typename C, EnableFuncIf< has_size_method<C>::value, 1>... >
std::size_t size_at_least( C&& c ) {
return c.size();
}
template<typename C, EnableFuncIf< !has_size_method<C>::value &&
std::is_base_of< std::random_access_iterator_tag, IteratorCategory<Iterator<C>> >::value, 2>... >
std::size_t size_at_least( C&& c ) {
using std::begin; using std::end;
return end(c)-begin(c);
};
template<typename C, EnableFuncIf< !has_size_method<C>::value &&
!std::is_base_of< std::random_access_iterator_tag, IteratorCategory<Iterator<C>> >::value, 3>... >
std::size_t size_at_least( C&& c ) {
return 0;
};
template < typename It >
auto try_make_move_iterator(It i, std::true_type)
-> decltype(make_move_iterator(i))
{
return make_move_iterator(i);
}
template < typename It >
It try_make_move_iterator(It i, ...)
{
return i;
}
#include <iostream>
template<typename C1, typename C2>
C1&& append_containers( C1&& c1, C2&& c2 )
{
using std::begin; using std::end;
try_reserve( c1, size_at_least(c1) + size_at_least(c2) );
using is_rvref = std::is_rvalue_reference<C2&&>;
c1.insert( end(c1),
try_make_move_iterator(begin(c2), is_rvref{}),
try_make_move_iterator(end(c2), is_rvref{}) );
return std::forward<C1>(c1);
}
struct append_infix_op {} append;
template<typename LHS>
struct append_on_right_op {
LHS lhs;
template<typename RHS>
LHS&& operator=( RHS&& rhs ) {
return append_containers( std::forward<LHS>(lhs), std::forward<RHS>(rhs) );
}
};
template<typename LHS>
append_on_right_op<LHS> operator+( LHS&& lhs, append_infix_op ) {
return { std::forward<LHS>(lhs) };
}
template<typename LHS,typename RHS>
typename std::remove_reference<LHS>::type operator+( append_on_right_op<LHS>&& lhs, RHS&& rhs ) {
typename std::decay<LHS>::type retval = std::forward<LHS>(lhs.lhs);
return append_containers( std::move(retval), std::forward<RHS>(rhs) );
}
template<typename C>
void print_container( C&& c ) {
for( auto&& x:c )
std::cout << x << ",";
std::cout << "\n";
};
int main() {
std::vector<int> a = {0,1,2};
std::vector<int> b = {3,4,5};
print_container(a);
print_container(b);
a +append= b;
const int arr[] = {6,7,8};
a +append= arr;
print_container(a);
print_container(b);
std::vector<double> d = ( std::vector<double>{-3.14, -2, -1} +append= a );
print_container(d);
std::vector<double> c = std::move(d) +append+ a;
print_container(c);
print_container(d);
std::vector<double> e = c +append+ std::move(a);
print_container(e);
print_container(a);
}
hehe.
Now with move-data-from-rhs, append-array-to-container, append forward_list-to-container, move-container-from-lhs, thanks to #DyP's help.
Note that the above does not compile in clang thanks to the EnableFunctionIf<>... technique. In clang this workaround works.
If you would like to add vector to itself both popular solutions will fail:
std::vector<std::string> v, orig;
orig.push_back("first");
orig.push_back("second");
// BAD:
v = orig;
v.insert(v.end(), v.begin(), v.end());
// Now v contains: { "first", "second", "", "" }
// BAD:
v = orig;
std::copy(v.begin(), v.end(), std::back_inserter(v));
// std::bad_alloc exception is generated
// GOOD, but I can't guarantee it will work with any STL:
v = orig;
v.reserve(v.size()*2);
v.insert(v.end(), v.begin(), v.end());
// Now v contains: { "first", "second", "first", "second" }
// GOOD, but I can't guarantee it will work with any STL:
v = orig;
v.reserve(v.size()*2);
std::copy(v.begin(), v.end(), std::back_inserter(v));
// Now v contains: { "first", "second", "first", "second" }
// GOOD (best):
v = orig;
v.insert(v.end(), orig.begin(), orig.end()); // note: we use different vectors here
// Now v contains: { "first", "second", "first", "second" }