C++ analogue of mapping function - c++

I'm surprised that I didn't find map function in standard C++ lib. Now I'm using this solution
template <typename Container, typename InputIterator, typename UnaryPredicate>
Container filter(InputIterator _from, InputIterator _to, UnaryPredicate _pred)
{
Container collection;
return std::accumulate(_from, _to, collection,
[_pred] (Container acc, const InputIterator::value_type & val) -> Container
{
if (_pred(val))
acc.insert(std::end(acc), val);
return acc;
});
}
//////////////////////////////
// usage
std::vector<int> vec = {0, 1, 2, 3};
std::vector<int> newVec = filter<decltype(newVec)>(std::begin(vec), std::end(vec),
[] (int n)
{
return n % 2 == 0;
});
but maybe some more common solution exists
edit : as is said below, it's filtering function. Okay, here is my map implementation:
template <typename T, typename MapFunction>
T map(T source, MapFunction func)
{
T collection;
for (auto val : source)
{
collection.insert(std::end(collection), func(val));
}
return collection;
}
so problem with std::transform and others that they changes source collection, but they should return another one.

The closest to the map (builtin of python, for example) would be std::for_each or std::transform, applying a function to a range defined by an iterators pair:
Example from en.cppreference.com, for a transform in-place:
int main()
{
std::string s("hello");
std::transform(s.begin(), s.end(), s.begin(), std::ptr_fun<int, int>(std::toupper));
std::cout << s;
}
Or a for_each with a lambda function, here we increment each element by 1:
int main()
{
std::vector<int> nums{3, 4, 2, 9, 15, 267};
std::for_each(nums.begin(), nums.end(), [](int &n){ n++; });
}
Part of the <algorithm> header.

Related

does C++ have spread operator?

can you do this in C++:
vector<int> v1={1,2}, v2={3,4};
vector<int> v3={...v1, ...v2, 5};
//v3 = {1,2,3,4,5}
What is the simplest way to do this with C++ ?
I would implement it with a helper function like this. Online demo here : https://onlinegdb.com/AnA3GkbQL
This template code kind of writes out all the individual push_backs and inserts needed to get the final result (at compile time).
#include <iostream>
#include <vector>
namespace details
{
template<typename type_t, typename arg_t, typename... args_t>
auto make_spread_impl(std::vector<type_t>& values, const arg_t& arg, const args_t&... args)
{
// check if template argument is a value or a std::vector of values.
if constexpr (std::is_same_v<arg_t, type_t>)
{
// single value
values.push_back(arg);
}
else
{
// vector of values
static_assert(std::is_same_v<std::vector<type_t>, arg_t>);
// append values to end
values.insert(values.end(), arg.begin(), arg.end());
}
// continue recursion
if constexpr (sizeof...(args_t) > 0)
{
return make_spread_impl(values, args...);
}
// recursion end condition
return values;
}
}
template<typename type_t, typename... args_t>
auto make_spread(const args_t&... args)
{
// one argument return a vector of values.
if constexpr (sizeof...(args) == 1ul)
{
return std::vector<type_t>{args...};
}
// otherwise recurse
std::vector<type_t> values;
details::make_spread_impl(values, args...);
return values;
}
int main()
{
std::vector<int> v1{ 1,2,3 };
std::vector<int> v2{ 5,6,7 };
auto result = make_spread<int>(v1, 4, v2, 8);
for (const auto& value : result)
{
std::cout << value << " ";
}
return 0;
}
No spread operator in C++.
Probably the simplest way would be a sequence of inserts
std::vector<int> v3;
v3.insert(v3.end(), v1.begin(), v1.end());
v3.insert(v3.end(), v2.begin(), v2.end());
v3.insert(v3.end(), 5);
Various range libraries have a concat function
auto v3 = ranges::views::concat(v1, v2, { 5 }) |
ranges::views::join |
ranges::views::to<vector>;
C++23 or ranges::v3. Still more verbose than spread operator.

Insert into vector with conditional iterator

Say I have a vector with various entries, which I want to insert into another vector, while leaving out entries that satisfy a condition.
For example, I want to insert a vector while leaving out all three's.
{1, 3, 2, 3, 4, 5, 3} -> { /* previous content, */ 1, 2, 4, 5}
What I came up with so far uses std::partition, which does not preserve the relative order and rearranges the source vector.
std::vector<int> source({1, 3, 2, 3, 4, 5, 3});
std::vector<int> target;
auto partition = std::partition(std::begin(source),
std::end(source), [](const auto& a) { return a == 3; });
target.insert(std::begin(target), partition, std::end(source));
What I am looking for is more of an iterator that checks a condition and moves on if the condition is not satisfied. Something like this:
target.insert(std::begin(target),
conditional_begin(source, [](const auto& a) { return a != 3; }),
conditional_end(source));
I suppose a conditional_end function would be necessary, since std::end would return a different iterator type than conditional_begin.
Maybe I have overlooked something, so my questions are:
Does the standard library provide something similar?
Is there a different easy way to achieve my goal?
Is there an easy way to implement the conditional iterator functionality?
Is there a different easy way to achieve my goal?
Yes, the standard already has this functionality built in. The function you are looking for is std::copy_if.
std::vector<int> source({1, 3, 2, 3, 4, 5, 3});
std::vector<int> target;
std::copy_if(source.begin(),
source.end(),
std::back_inserter(target), [](auto val){ return val != 3; });
Here, std::back_inserter(target), will call push_back on target for each element that the predicate returns true.
Yes, you can create a custom iterator that does what you want but it is currently a little tedious to create custom iterators using standard C++. It would look something like this:
template <typename Itr, typename F>
struct ConditionalIterator {
Itr itr;
Itr end;
F condition;
using value_type = typename Itr::value_type;
using difference_type = typename Itr::difference_type;
using pointer = typename Itr::pointer;
using reference = typename Itr::reference;
using iterator_category = std::forward_iterator_tag;
ConditionalIterator() = default;
ConditionalIterator(Itr itr, Itr end, F condition): itr(itr), end(end), condition(condition) {}
bool operator!=(const ConditionalIterator &other) const { return other.itr != itr; }
reference operator*() const { return *itr; }
pointer operator->() const { return &(*itr); }
ConditionalIterator& operator++() {
for (; ++itr != end;) {
if (condition(*itr))
break;
}
return *this;
}
ConditionalIterator operator++(int) {
ConditionalIterator ret(*this);
operator++();
return ret;
}
};
You can then create something like the conditional_begin and conditional_end helper functions you asked for. The only issue is that std::vector::insert expects the two iterators to have the same type. If we use a lambda for our condition then this will be part of the type of our conditional iterator. So we need to pass the lambda to both helper functions so that they return iterators with matching types:
template <typename C, typename F>
auto conditional_begin(const C &source, F f) {
return ConditionalIterator<typename C::const_iterator, F>(source.begin(),
source.end(), f);
}
template <typename C, typename F>
auto conditional_end(const C &source, F f) {
return ConditionalIterator<typename C::const_iterator, F>(source.end(),
source.end(), f);
}
Which you could call with a lambda like this:
auto condition = [](const auto &a) { return a != 3; };
target.insert(std::begin(target),
conditional_begin(source, std::ref(condition)),
conditional_end(source, std::ref(condition)));
Live demo.
My crude tests show, in this case, this ends up being significantly faster than simply using copy_if and back_inserter because std::vector::insert first works out how much memory to allocate before inserting. Just using back_inserter will cause multiple memory allocations. The difference in performance will depend on how expensive the condition is to evaluate. You can get the same speedup by using count_if to reserve enough space before using copy_if:
auto count = static_cast<size_t>(std::count_if(source.begin(),
source.end(), condition));
target.reserve(target.size() + count);
std::copy_if(source.begin(),
source.end(),
std::back_inserter(target), condition);
Live demo.
As ranges will be standardized soon, this is an alternative using range-v3, the reference library for the proprosal:
#include <range/v3/view/concat.hpp>
#include <range/v3/view/filter.hpp>
using namespace ranges;
const std::vector<int> source{1, 3, 2, 3, 4, 5, 3};
const std::vector<int> target = view::concat(source,
source | view::filter([](auto i){ return i != 3; }));

How to combine back_inserter with a transformation, C++

How can I wrap an OutputIterator such as back_inserter_iterator with a transformation?
Consider
std::vector<double> xx;
std::vector<double> yy;
std::vector<double> diff;
auto ba = std::back_inserter(diff);
std::set_difference(xx.begin(), xx.end(), yy.begin(), yy.end(), ba);
I would like to apply a free function f(double) or g(std::vector<double>::iterator) before pushing back to the diff vector:
Specifically, how can I store the addresses of the diff elements (or iterators) instead of the elements themeselves.
std::vector<double&> diff;
auto baAdr = ??? std::back_inserter( ??? (diff));
std::set_difference(xx.begin(), xx.end(), yy.begin(), yy.end(), baAdr);
For performance reasons (the real data is big) I do not want to construct a temporary vector and std::transform from it. It would also not work for non-copyable, movable types.
I can use boost.
With boost::function_output_iterator:
#include <vector>
#include <algorithm>
#include <boost/function_output_iterator.hpp>
int main()
{
std::vector<double> xx;
std::vector<double> yy;
std::vector<const double*> diff; // const pointers, or else you
// need a const_cast in lambda
std::set_difference(xx.begin(), xx.end(), yy.begin(), yy.end(),
boost::make_function_output_iterator(
[&diff](const double& d) { diff.push_back(&d); }
)
);
}
There's probably something built in to boost, but here's my hacky attempt to write my own iterator:
template <typename T, typename FN>
struct transform_iterator {
transform_iterator(T &t, FN fn)
: _t{t}
, _fn{std::move(fn)} { }
transform_iterator<T, FN>& operator * () { return *this; }
transform_iterator<T, FN>& operator ++ () { return *this; }
template <typename V>
transform_iterator<T, FN>& operator = (V const &v) {
_t.push_back(_fn(v));
return *this;
}
T &_t;
FN _fn;
};
This will take a function and execute it whenever something tries to assign to the iterator (I think this is how things like back_inserter usually work). A trivial helper function can create the iterators:
template <typename T, typename FN>
auto make_transform_iterator(T &t, FN fn) {
return transform_iterator<T, FN>{t, std::move(fn)};
};
Lastly, iterator_traits needs to be specialized so transform_iterator will work with algorithms.
namespace std {
template <typename T, typename FN>
struct iterator_traits<transform_iterator<T, FN>> {
using value_type = typename T::value_type;
};
}
There are more types that need to be set in iterator_traits, but this was sufficient for my testing; your mileage will vary.
My main looks like this:
int main() {
std::vector<int> xx{1, 2, 3};
std::vector<int> yy{1, 3, 5};
std::vector<int> diff;
auto ba = make_transform_iterator(diff, [](auto v) { return v + 10; });
std::set_difference(std::begin(xx), std::end(xx),
std::begin(yy), std::end(yy),
ba);
for(auto const &v: diff) {
std::cout << v << '\n';
}
return 0;
}
You could expand this to work with generic output iterators instead of just types that support push_back.

Using std algorithm library for unique equivalence with respect to binary relation

I have binary relation on some type T induced by a function equivalent:
bool equivalent(T const& a, T const& b); // returns true if a and b are equivalent
It has the properties that
equivalent(a, a) == true
and
equivalent(a, b) == equivalent(b, a)
for all a, b.
For a given collection of elements of type T, I want to remove all but the first occurrence of each equivalence class. I have come up with the following Code but was wandering:
Is there is a solution without an explicit loop?
std::vector<T> filter_all_but_one_for_each_set_of_equivalent_T(std::vector<T> const& ts) {
std::vector<T> result;
for (auto iter = ts.begin(); iter != ts.end(); ++iter) {
auto const& elem = *iter;
bool has_equivalent_element_at_earlier_position = std::any_of(
ts.begin(),
iter,
&equivalent
);
if (not has_equivalent_element_at_earlier_position) {
result.push_back(routing_pin);
}
}
return result;
}
Update
As far as I understand std::unique won't do because my type T is not sortable. And because I only have C++11 in my case, but I would be interested in other options too for education.
Here's a way that only has one very simple loop:
First define our class, which I'll call A instead of T because T is typically used for templates:
class A{
public:
explicit A(int _i) : i(_i){};
int get() const{return i;}
private:
int i;
};
And then our equivalent function just compares the integers for equality:
bool equivalent(A const& a, A const& b){return a.get() == b.get();}
next I'll define the filtering function.
The idea here is to take advantage of std::remove to do the looping and erasing efficiently for us (it typically swaps elements to the end so that you are not shifting the vector for each removal).
We start by removing everything that matches the first element, then afterwards remove everything that matches the second element (which is guaranteed != to the first element now), and so on.
std::vector<A> filter_all_but_one_for_each_set_of_equivalent_A(std::vector<A> as) {
for(size_t i = 1; i < as.size(); ++i){
as.erase(std::remove_if(as.begin() + i, as.end(), [&as, i](const A& next){return equivalent(as[i-1], next);}), as.end());
}
return as;
}
Demo
Edit: As Richard Hodges mentioned, it is possible to delay any erasing until the very end. I couldn't make it look as beautiful though:
std::vector<A> filter_all_but_one_for_each_set_of_equivalent_A(std::vector<A> as) {
auto end = as.end();
for(size_t i = 1; i < std::distance(as.begin(), end); ++i){
end = std::remove_if(as.begin() + i, end, [&as, i](const A& next){return equivalent(as[i-1], next);});
}
as.erase(end, as.end());
return as;
}
Demo 2
Expanding on my comment in AndyG's answer:
template<class T, class A, class Equivalent>
auto deduplicated2(std::vector<T, A> vec, Equivalent&& equivalent) -> std::vector<T, A>
{
auto current = std::begin(vec);
// current 'last of retained sequence'
auto last = std::end(vec);
while (current != last)
{
// define a predicate which checks for equivalence to current
auto same = [&](T const& x) -> bool
{
return equivalent(*current, x);
};
// move non-equivalent items to end of sequence
// return new 'end of valid sequence'
last = std::remove_if(std::next(current), last, same);
}
// erase all items beyond the 'end of valid sequence'
vec.erase(last, std::end(vec));
return vec;
}
Credit to AndyG please.
For very large vectors where T is hashable, we can aim for an O(n) solution:
template<class T, class A, class Equivalent>
auto deduplicated(std::vector<T, A> const& vec, Equivalent&& equivalent) -> std::vector<T, A>
{
auto seen = std::unordered_set<T, std::hash<T>, Equivalent>(vec.size(), std::hash<T>(), std::forward<Equivalent>(equivalent));
auto result = std::vector<T, A>();
result.resize(vec.size());
auto current = std::begin(vec);
while (current != std::end(vec))
{
if (seen.insert(*current).second)
{
result.push_back(*current);
}
}
return result;
}
Finally, revisiting the first solution and refactoring into sub-concerns (I can't help myself):
// in-place de-duplication of sequence, similar interface to remove_if
template<class Iter, class Equivalent>
Iter inplace_deduplicate_sequence(Iter first, Iter last, Equivalent&& equivalent)
{
while (first != last)
{
// define a predicate which checks for equivalence to current
using value_type = typename std::iterator_traits<Iter>::value_type;
auto same = [&](value_type const& x) -> bool
{
return equivalent(*first, x);
};
// move non-equivalent items to end of sequence
// return new 'end of valid sequence'
last = std::remove_if(std::next(first), last, same);
}
return last;
}
// in-place de-duplication on while vector, including container truncation
template<class T, class A, class Equivalent>
void inplace_deduplicate(std::vector<T, A>& vec, Equivalent&& equivalent)
{
vec.erase(inplace_deduplicate_sequence(vec.begin(),
vec.end(),
std::forward<Equivalent>(equivalent)),
vec.end());
}
// non-destructive version
template<class T, class A, class Equivalent>
auto deduplicated2(std::vector<T, A> vec, Equivalent&& equivalent) -> std::vector<T, A>
{
inplace_deduplicate(vec, std::forward<Equivalent>(equivalent));
return vec;
}
You can try this one. The trick here is to obtain the index while inside predicate.
std::vector<T> output;
std::copy_if(
input.begin(), input.end(),
std::back_inserter(output),
[&](const T& x) {
size_t index = &x - &input[0];
return find_if(
input.begin(), input.begin() + index, x,
[&x](const T& y) {
return equivalent(x, y);
}) == input.begin() + index;
});
Since performance is not an issue, you can use std::accumulate to scan through the elements and add them to an accumulator vector xs if there is not already
an equaivalent element in xs.
With this you don't need any hand-written raw loops at all.
std::vector<A> filter_all_but_one_for_each_set_of_equivalent_A(std::vector<A> as) {
return std::accumulate(as.begin(), as.end(),
std::vector<A>{}, [](std::vector<A> xs, A const& x) {
if ( std::find_if(xs.begin(), xs.end(), [x](A const& y) {return equivalent(x,y);}) == xs.end() ) {
xs.push_back(x);
}
return xs;
});
}
With two helper functions this becomes actually readable:
bool contains_equivalent(std::vector<A> const& xs, A const& x) {
return std::find_if(xs.begin(), xs.end(),
[x](A const& y) {return equivalent(x,y);}) != xs.end();
};
std::vector<A> push_back_if(std::vector<A> xs, A const& x) {
if ( !contains_equivalent(xs, x) ) {
xs.push_back(x);
}
return xs;
};
The function itself is just a call to std::accumulate:
std::vector<A> filter_all_but_one_for_each_set_of_equivalent_A(std::vector<A> as) {
return std::accumulate(as.begin(), as.end(), std::vector<A>{}, push_back_if);
}
I've modified AndyG's example code with my proposed function.
As defined above, std::accumulate calls push_back_if with a copy of the accumulator variable, and the return value is move-assigned to the accumulator again. This is very inefficient, but can be optimized by changing push_back_if to take a reference so that the vector is modified in-place. The initial value needs to be passed as a reference wrapper with std::ref to eliminate remaining copies.
std::vector<A>& push_back_if(std::vector<A>& xs, A const& x) {
if ( !contains_equivalent(xs, x) ) {
xs.push_back(x);
}
return xs;
};
std::vector<A> filter_all_but_one_for_each_set_of_equivalent_A(std::vector<A> const& as) {
std::vector<A> acc;
return std::accumulate(as.begin(), as.end(), std::ref(acc), push_back_if);
}
You can see in the example that the copy-constructor is almost completely eliminated.
First coming up with another loop version, in contrast to your own, it unifies in place, you might find it interesting:
std::vector<int> v({1, 7, 1, 8, 9, 8, 9, 1, 1, 7});
auto retained = v.begin();
for(auto i = v.begin(); i != v.end(); ++i)
{
bool isFirst = true;
for(auto j = v.begin(); j != retained; ++j)
{
if(*i == *j)
{
isFirst = false;
break;
}
}
if(isFirst)
{
*retained++ = *i;
}
}
v.erase(retained, v.end());
This was the base for a version using std::remove_if and std::find_if:
auto retained = v.begin();
auto c = [&v, &retained](int n)
{
if(std::find_if(v.begin(), retained, [n](int m) { return m == n; }) != retained)
return true;
// element remains, so we need to increase!!!
++retained;
return false;
};
v.erase(std::remove_if(v.begin(), v.end(), c), v.end());
You need the lambda in this case, as we need a unique-predicate, whereas equivalent (in my int example represented by operator==) is a binary one...
struct S {
int eq;
int value;
bool operator==(const S& other) const { return eq == other.eq; }
};
namespace std {
template <> struct hash<S>
{
size_t operator()(const S &s) const
{
return hash<int>()(s.eq);
}
};
}
array<S, 6> as{ { {1,0},{2,0},{3,0},{ 1,1 },{ 2,1 },{ 3,1 } } };
unordered_set<S> us(as.cbegin(), as.cend());

C++ algorithm for applying a function to consecutive elements

Is there a simpler way to write this, e.g. by using an STL or boost algorithm?
std::vector<int> v { 0, 1, 2, 3 }; // any generic STL container
std::vector<int> result;
std::transform(v.begin(), v.end() - 1, // (0, 1, 2)
v.begin() + 1, // (1, 2, 3)
std::back_inserter(result),
[](int a, int b){ return a + b; }); // any binary function
// result == { 1, 3, 5 }
I propose using a for loop:
for(std::vector::size_type i = 0; i < v.size() - 1; i++)
result.push_back(v[i] + v[i+1])
A more generic loop for bidirectional iterators:
// let begin and end be iterators to corresponding position
// let out be an output iterator
// let fun be a binary function
for (auto it = begin, end_it = std::prev(end); it != end_it; ++it)
*out++ = fun(*it, *std::next(it));
We can go a bit further and write a loop for forward iterators:
if(begin != end) {
for (auto curr = begin,
nxt = std::next(begin); nxt != end; ++curr, ++nxt) {
*out++ = fun(*curr, *nxt);
}
}
Finally, and algorithm for input iterators. However, this one requires that the value type is copyable.
if(begin != end) {
auto left = *begin;
for (auto it = std::next(begin); it != end; ++it) {
auto right = *it;
*out++ = fun(left, right);
left = right;
}
}
The binary version of std::transform can be used.
The std::adjacent_find/std::adjacent_difference algorithms can be abused.
std::adjacent_difference is for exactly this, but as you mentioned, it copies the first element to the result, which you don't want.
Using Boost.Iterator, it's pretty easy to make a back_inserter which throws away the first element.
#include <boost/function_output_iterator.hpp>
template <class Container>
auto mybackinsrtr(Container& cont) {
// Throw away the first element
return boost::make_function_output_iterator(
[&cont](auto i) -> void {
static bool first = true;
if (first)
first = false;
else
cont.push_back(i);
});
}
Then you can #include <boost/range/numeric.hpp> and do this:
std::vector<int> v { 0, 1, 2, 3 }; // any generic STL container
std::vector<int> result;
boost::adjacent_difference(v, mybackinsrtr(result), std::plus<>{}); // any binary function
See it on ideone
When you want your binary function to return a different type (such as a string), the above solution won't work because, even though the insertion cont.push_back(i) is never called for the first copied element, it still must be compiled and it won't go.
So, you can instead make a back_inserter that ignores any elements of a different type than go in the container. This will ignore the first, copied, element, and accept the rest.
template <class Container>
struct ignore_insert {
// Ignore any insertions that don't match container's type
Container& cont;
ignore_insert(Container& c) : cont(c) {}
void operator() (typename Container::value_type i) {
cont.push_back(i);
}
template <typename T>
void operator() (T) {}
};
template <class Container>
auto ignoreinsrtr(Container& cont) {
return boost::make_function_output_iterator(ignore_insert<Container>{cont});
}
Then you can use it similarly.
std::vector<int> v { 0, 1, 2, 3 }; // any generic STL container
std::vector<std::string> result;
boost::adjacent_difference(v, ignoreinsrtr(result), [](int a, int b){ return std::to_string(a+b); });
On ideone
I would write your own algorithm to apply a functor to each pair of elements in the container.
(Shameless blurb) In my ACCU presentation this year, "STL Algorithms – How to Use Them and How to Write Your Own", showed how to write one like this. I called it adjacent_pair (about 25:00 into the video)
template <typename ForwardIterator, typename Func>
void adjacent_pair(ForwardIterator first, ForwardIterator last, Func f)
{
if (first != last)
{
ForwardIterator trailer = first;
++first;
for (; first != last; ++first, ++trailer)
f(*trailer, *first);
}
}
Stephan T. Lavavej has written a nice adjacent_iterator class here:
How do I loop over consecutive pairs in an STL container using range-based loop syntax?
This could also be used here.