c++ boost conditional remove from container - c++

i want to do something like c# linq style :
SomeColection <SomeType> someColection;
someColection.Remove(something => something > 2);
and it'll remove all the things that are bigger then 2 (or any other boolean condition)...
using boost in the project...

C++0x (using lambdas):
container.erase( std::remove_if( container.begin(), container.end(),
[]( int v ) { return v > 2; } ),
container.end() );
The reason for the erase combined with the remove_if is that STL algorithms apply to iterators, and not containers. They relocate the contents of the container, but they do not modify the container per-se.
C++03:
container.erase( std::remove_if( container.begin(), container.end(),
std::bind2nd( std::greater<int>(), 2 ) ),
container.end() );
This may seem a little simpler, but it is also less flexible, as there are only so many predicates already defined. For more complex operations you would have to write your own predicate functor.

You don't need boost (unless your main focus is that inline anonymous function). Plain STL is fine.
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
int main () {
std::vector<int> x (24);
for (int i = 0; i < x.size(); ++ i)
x[i] = i % 5;
std::vector<int>::iterator
new_end = std::remove_if(x.begin(), x.end(),
std::bind2nd(std::greater<int>(), 2));
x.erase(new_end, x.end());
for (int i = 0; i < x.size(); ++ i)
std::cout << x[i] << " ";
return 0;
}
With boost you can replace the bind2nd stuff with
#include <boost/lambda/lambda.hpp>
...
using boost::lambda::_1;
std::vector<int>::iterator new_end = std::remove_if(x.begin(), x.end(), _1 > 2);

First, you need a simple template wrapper:
template <class Container, class UnaryPredicate>
void erase_if(Container& container, UnaryPredicate pred)
{
container.erase(
std::remove_if(container.begin(), container.end(), pred),
container.end()
);
}
It's a well-known idiom, however it won't be possible with map or set as they maintain their own order.
Then, you can use Boost.Lambda to get the syntax you wish for writing the predicate itself.
using boost::lambda::_1;
SomeCollection<Type> someCollection;
erase_if(someCollection, _1 > 2);

By the way, boost::range v.1.46.0 (released in 2011) has exactly what you want - the remove_erase_if algorithm
#include <boost/range/algorithm_ext/erase.hpp
std::vector<int> vec = {1, 6, 2, 7};
boost::range::remove_erase_if(vec, [](int val){return val > 5;});
Short and straightforward.

Related

How to use std::transform with container without push_back?

I have a container that has no push_back() method. But this container has an iterator on begin()and end().
I would like to use std::transform() to output into that container. But std::back_inserter needs to call push_back() on the output container.
Is it possible to use std::transform() to output into a container that just supports direct assignment? Like:
for (auto item : containerNoPushBack)
{
item = calculateValue();
}
Or indexed assignment like:
for (size_t i = 0; i < containerNoPushBack.size(); ++i)
{
item[i] = calculateValue();
}
If you can do item[i] (i.e. your container has enough elements in it), then you can simply use your_container.begin() in std::transform, no need for std::back_inserter. std::back_inserter is just a nice way to avoid explicitly resizing containers before applying it.
The following snippets will both fill my_output with contents of my_input:
std::vector<int> my_output;
std::transform(my_input.begin(), my_input.end(), std::back_inserter(my_output), [](const auto& arg){return arg;});
std::vector<int> my_output;
my_output.resize(my_input.size());
std::transform(my_input.begin(), my_input.end(), my_output.begin(), [](const auto& arg){return arg;});
Just use a plain std::transform with begin and end iterators. No need for std::back_inserter or even an std::inserter.
For example, std::array does not support the push_back method, but std::transform works on it:
#include <iostream>
#include <array>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> data = {1, 2, 3, 4, 5};
std::array<int, 5> arr{};
// note the lack of std::back_inserter just below
std::transform(data.cbegin(), data.cend(), arr.begin(),
[](auto i) {
return i * i;
});
for (const auto i : arr) {
std::cout << i << ' '; // prints 1, 4, 9, 16, 25
}
}
std::transform does use "direct assignment". only if you need to push the elements you would use a back_inserter, if the target has already elements you dont need that.
Consider the possible implementation (taken from cppreference):
template<class InputIt, class OutputIt, class UnaryOperation>
OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first,
UnaryOperation unary_op)
{
while (first1 != last1) {
*d_first++ = unary_op(*first1++);
}
return d_first;
}
std::transform itself does not push anything. Exactly for that reason you need a back_inserter. However, instead you can resize the target to have enough space for the transformed elements.

Using the value that any_of finds to use in a return outside lambda

A working piece of code:
std::vector<double>::iterator it = std::find_if(intersections.begin(), intersections.end(), [&](const double i) {return i >= 0;});
if (it != intersections.end())
return rayOrigin + *(it) * rayDirection);
But I would like to use something like this
Is there a way to capture the i in a clean way (not using a temp variable), that the any_of finds here to use it in the return statement
if (std::any_of(intersections.begin(), intersections.end(), [&](const double i) {return i >= 0;}))
return rayOrigin + i * rayDirection);
I'd write a range-based searcher that returns an object which can be * dereferenced (maybe more than once) to get the found thing, or evaluated in a bool context to determine if it was found.
In my experience this makes code cleaner, and makes the common case of "I want to know if it is there" simpler, yet permits you to get at the item tersely:
template<class Range, class F>
auto linear_search_if( Range&& r, F&& f )
// remove next line in C++14, it removes ADL `begin` capability:
-> typename std::iterator_traits<decltype( std::begin(r) )>::value_type*
// reproducing ADL begin in C++11 is a pain, so just use the above line
{
using std::begin; using std::end;
using iterator = decltype(begin(r));
using T = typename std::iterator_traits<iterator>::value_type;
using R = T*; // in C++17 I prefer std::optional<iterator>;
iterator it = std::find_if( begin(r), end(r), std::forward<F>(f) );
if (it != end(r))
return R(std::addressof(*it)); // return R(it); in C++17
else
return R(nullptr); // return R{}; in C++17
}
if (auto pi = linear_search_if( intersections, [&](auto i){return i>=0;})
return rayOrigin + *pi * rayDirection; // **pi in C++17
Yes, you do a *pi instead of just an i.
Yes the current ways of find_if and any_of are slightly annoying. #Yakk's solution works by writing a wrapper around std::find_if that returns a std::optional<int> to both test for success and conditionally extract the result. This is certainly a way forward for a next version of the STL.
However, in C++17, you can move initializers into selection statements which eliminates most of the pain already:
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
auto const v = std::vector<int> { -2, -1, 0, 1, 2 };
auto const pred = [&](const int i) { return i >= 0; };
if (auto const it = std::find_if(v.begin(), v.end(), pred); it != v.end())
std::cout << *it << '\n';
}
Live Example using a recent Clang in c++1z mode.

create container from another container, applying each element some function in c++

My question is simple, see example:
std::array<int,6> a = {{0,1,2,3,4,5}}; // -- given container.
auto F = []( int i ) { return i*i; }; // -- given function.
std::vector<int> v; // need create
// my solution:
v.reserve( a.size () );
for( std::size_t i = 0; i < a.size(); ++i )
v.push_back( F(a[i]) );
// but I need something like
std::vector<int>v( a.begin(), a.end(), <|applying each element to F|> );
Can I create container something like above not calling reserve explicitly and any reallocation?
EDIT:
I want avoid reserve; because othercase my first solution is good
for me :)
I want avoid any resize; because it's initialzed each
element by default ctor.
I will use this in the real project which may included many 3-rd party libraries ( boost, Soft-STL, ...).
The standard algorithm std::transform does exactly this!
std::vector<int> v(a.size());
std::transform(
std::begin(a), std::end(a),
std::begin(v),
F
);
You can start with an empty vector and use std::back_inserter, if you like:
std::vector<int> v;
std::transform(
std::begin(a), std::end(a),
std::back_inserter(v),
F
);
But you're subjecting yourself to needless re-allocations if you do that (unless you reserve first, as in your original attempt). You can decide for yourself what your priority is.
Use std::transform:
#include <algorithm> // std::transform
#include <iterator> // std::back_inserter
....
transform(a.begin(), a.end(), back_inserter(v), F);
You may want to call v.reserve(asize()) first to avoid re-allocations.
Another solution is to use boost::transform_iterator. The benefit is that you can pass iterators to the container constructor. That avoids memory reallocations compared to when using std::back_inserter or having to call reserve or resize on the destination. All in one statement:
std::vector<int> result(
boost::make_transform_iterator(std::begin(a), F)
, boost::make_transform_iterator(std::end(a), F)
);
You can achieve terser syntax though, like this:
std::vector<int> result(transform_range(a, F));
transform_range implementation:
template<class Iterator>
struct AutoSequence
{
Iterator const beg_, end_;
template<class T>
operator std::vector<T>() const {
return {beg_, end_};
}
};
template<class Function, class InSeq>
auto transform_range(InSeq const& in) -> AutoSequence<decltype(boost::make_transform_iterator<Function>(in.begin()))> {
return {
boost::make_transform_iterator<Function>(std::begin(in))
, boost::make_transform_iterator<Function>(std::end(in))
};
}
template<class Function, class InSeq>
auto transform_range(InSeq const& in, Function&& f) -> AutoSequence<decltype(boost::make_transform_iterator(in.begin(), f))> {
return {
boost::make_transform_iterator(std::begin(in), f)
, boost::make_transform_iterator(std::end(in), f)
};
}

how to pass a predicate to algorithm

I'm having a problem passing predicate using lambda, I'm trying to move element that matches the predicate to the beginning of a second container, but it didn't seem to work, so what's wrong please?
#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include <utility>
#include <algorithm>
using namespace std;
template <typename iterator, typename Container, typename T>
void move_if(iterator b, iterator e, Container o, T pred)
{
if(pred)
{
o.insert(o.begin(),pred);
}
}
int main()
{
vector<int>v{1,2,3,4,5,6,7,8,9,10};
vector<int>v2;
for (auto i=v.begin(); i !=v.end(); ++i)
save_if(v.begin(), v.end(), v2, []( vector<int>::iterator i){return (*i>5);});
return 0;
}
Try this...
int main()
{
std::vector<int> v{1,2,3,4,5,6,7,8,9,10};
std::vector<int> v2;
std::vector<int>::const_iterator
it = std::remove_copy_if(v.begin(), v.end(),
std::back_inserter(v2),
[](int const& i){return i <= 5;});
v.erase(it, v.end);
return 0;
}
You can read more about remove_copy_if on cppreference.com; it removes elements from the input range and copies them to the output unless the predicate returns true.
Note that this is an STL remove, so you need to call erase afterwards to shrink the input. The semantics of this solution are slightly different to the code you posted, but more similar to your description of what you wanted.
Check this out, I did some modifications on your code:
template <typename iterator, typename Container, typename T>
void move_if(iterator a, iterator b, Container &o, T pred)
{
for (auto i = a; i != b; i++)
{
if (pred(*i))
o.insert(o.begin(), *i);
}
}
int main()
{
vector<int>v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int>v2;
move_if(v.begin(), v.end(), v2, [](int i) { return !(i > 5); });
}
Note: As the comments, It's recommended to rename move_if to copy_if, if the functionality is as above code, otherwise you should really move items.
There is no overload of std::vector::insert that takes a predicate as second argument, so this line is wrong:
o.insert(o.begin(),pred);
Furthermore, the predicate needs to be called with an argument,
pred(someArg);
which in your case would be an std::vector<int>::iterator. Also, save_if is not the same as move_if. But more importantly, it isn't clear at all what you are trying to achieve.
In C++11, stateless lambdas like [](){return true} that do not capture anything can be implicitly converted to function pointers. When you do if(pred) you are converting your stateless lambda into a function pointer, checking if that pointer is non-null (it is non-null). This is not what you want to do.
Here is an implementation that moves things between b and e that pred(x) says should be moved:
template <typename iterator, typename Container, typename T>
void move_if(iterator b, iterator e, Container o, T pred)
{
for( auto i = b; i != e;++i) {
if(pred) {
o.insert(o.end(),std::move(*i));
}
}
}
Note that I inserted at o.end(), because the Container you want is probably vector, and inserting at the end() of vector is much faster.
In reality, you probably want to take an output iterator (and by default, use std::back_inserter from a Container) and output your data to that. Similarly, remove_move_if would be a better way to remove, shuffling the elements down the b-e range, and returning an iterator.
Finally, ranged-based algorithms are worth writing. Instead of taking a begin/end iterator pair, take a single object upon which begin(c) and end(c) have been overriden to return begin/end. If you are working on a sub-range, you can pass in a begin/end range of iterators struct with begin/end suitably overridden.

Copy map values to vector in STL [duplicate]

This question already has answers here:
How to retrieve all keys (or values) from a std::map and put them into a vector?
(24 answers)
Closed 1 year ago.
Working my way through Effective STL at the moment. Item 5 suggests that it's usually preferable to use range member functions to their single element counterparts. I currently wish to copy all the values in a map (i.e. - I don't need the keys) to a vector.
What is the cleanest way to do this?
You could probably use std::transform for that purpose. I would maybe prefer Neils version though, depending on what is more readable.
Example by xtofl (see comments):
#include <map>
#include <vector>
#include <algorithm>
#include <iostream>
template< typename tPair >
struct second_t {
typename tPair::second_type operator()( const tPair& p ) const { return p.second; }
};
template< typename tMap >
second_t< typename tMap::value_type > second( const tMap& m ) { return second_t< typename tMap::value_type >(); }
int main() {
std::map<int,bool> m;
m[0]=true;
m[1]=false;
//...
std::vector<bool> v;
std::transform( m.begin(), m.end(), std::back_inserter( v ), second(m) );
std::transform( m.begin(), m.end(), std::ostream_iterator<bool>( std::cout, ";" ), second(m) );
}
Very generic, remember to give him credit if you find it useful.
You can't easily use a range here because the iterator you get from a map refers to a std::pair, where the iterators you would use to insert into a vector refers to an object of the type stored in the vector, which is (if you are discarding the key) not a pair.
I really don't think it gets much cleaner than the obvious:
#include <map>
#include <vector>
#include <string>
using namespace std;
int main() {
typedef map <string, int> MapType;
MapType m;
vector <int> v;
// populate map somehow
for( MapType::iterator it = m.begin(); it != m.end(); ++it ) {
v.push_back( it->second );
}
}
which I would probably re-write as a template function if I was going to use it more than once. Something like:
template <typename M, typename V>
void MapToVec( const M & m, V & v ) {
for( typename M::const_iterator it = m.begin(); it != m.end(); ++it ) {
v.push_back( it->second );
}
}
With C++11 we have the fancy new for loop:
for (const auto &s : schemas)
names.push_back(s.second);
where schemas is a std::map and names is an std::vector.
This populates the array (names) with values from the map (schemas); change s.second to s.first to get an array of keys.
#include <algorithm> // std::transform
#include <iterator> // std::back_inserter
std::transform(
your_map.begin(),
your_map.end(),
std::back_inserter(your_values_vector),
[](auto &kv){ return kv.second;}
);
Sorry that I didn't add any explanation - I thought that code is so simple that is doesn't require any explanation.
So:
transform( beginInputRange, endInputRange, outputIterator, unaryOperation)
this function calls unaryOperation on every item from inputIterator range (beginInputRange-endInputRange). The value of operation is stored into outputIterator.
If we want to operate through whole map - we use map.begin() and map.end() as our input range. We want to store our map values into vector - so we have to use back_inserter on our vector: back_inserter(your_values_vector). The back_inserter is special outputIterator that pushes new elements at the end of given (as paremeter) collection.
The last parameter is unaryOperation - it takes only one parameter - inputIterator's value. So we can use lambda:
[](auto &kv) { [...] }, where &kv is just a reference to map item's pair. So if we want to return only values of map's items we can simply return kv.second:
[](auto &kv) { return kv.second; }
I think this explains any doubts.
If you are using the boost libraries, you can use boost::bind to access the second value of the pair as follows:
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <boost/bind.hpp>
int main()
{
typedef std::map<std::string, int> MapT;
typedef std::vector<int> VecT;
MapT map;
VecT vec;
map["one"] = 1;
map["two"] = 2;
map["three"] = 3;
map["four"] = 4;
map["five"] = 5;
std::transform( map.begin(), map.end(),
std::back_inserter(vec),
boost::bind(&MapT::value_type::second,_1) );
}
This solution is based on a post from Michael Goldshteyn on the boost mailing list.
Using lambdas one can perform the following:
{
std::map<std::string,int> m;
std::vector<int> v;
v.reserve(m.size());
std::for_each(m.begin(),m.end(),
[&v](const std::map<std::string,int>::value_type& p)
{ v.push_back(p.second); });
}
Here is what I would do.
Also I would use a template function to make the construction of select2nd easier.
#include <map>
#include <vector>
#include <algorithm>
#include <memory>
#include <string>
/*
* A class to extract the second part of a pair
*/
template<typename T>
struct select2nd
{
typename T::second_type operator()(T const& value) const
{return value.second;}
};
/*
* A utility template function to make the use of select2nd easy.
* Pass a map and it automatically creates a select2nd that utilizes the
* value type. This works nicely as the template functions can deduce the
* template parameters based on the function parameters.
*/
template<typename T>
select2nd<typename T::value_type> make_select2nd(T const& m)
{
return select2nd<typename T::value_type>();
}
int main()
{
std::map<int,std::string> m;
std::vector<std::string> v;
/*
* Please note: You must use std::back_inserter()
* As transform assumes the second range is as large as the first.
* Alternatively you could pre-populate the vector.
*
* Use make_select2nd() to make the function look nice.
* Alternatively you could use:
* select2nd<std::map<int,std::string>::value_type>()
*/
std::transform(m.begin(),m.end(),
std::back_inserter(v),
make_select2nd(m)
);
}
One way is to use functor:
template <class T1, class T2>
class CopyMapToVec
{
public:
CopyMapToVec(std::vector<T2>& aVec): mVec(aVec){}
bool operator () (const std::pair<T1,T2>& mapVal) const
{
mVec.push_back(mapVal.second);
return true;
}
private:
std::vector<T2>& mVec;
};
int main()
{
std::map<std::string, int> myMap;
myMap["test1"] = 1;
myMap["test2"] = 2;
std::vector<int> myVector;
//reserve the memory for vector
myVector.reserve(myMap.size());
//create the functor
CopyMapToVec<std::string, int> aConverter(myVector);
//call the functor
std::for_each(myMap.begin(), myMap.end(), aConverter);
}
Why not:
template<typename K, typename V>
std::vector<V> MapValuesAsVector(const std::map<K, V>& map)
{
std::vector<V> vec;
vec.reserve(map.size());
std::for_each(std::begin(map), std::end(map),
[&vec] (const std::map<K, V>::value_type& entry)
{
vec.push_back(entry.second);
});
return vec;
}
usage:
auto vec = MapValuesAsVector(anymap);
I thought it should be
std::transform( map.begin(), map.end(),
std::back_inserter(vec),
boost::bind(&MapT::value_type::first,_1) );
We should use the transform function from STL algorithm, the last parameter of transform function could be a function object, function pointer or a lambda function that convert item of map to item of vector. This case map have items have type pair that need to convert to item that has int type for vector. Here is my solution that I use lambda function:
#include <algorithm> // for std::transform
#include <iterator> // for back_inserted
// Map of pair <int, string> need to convert to vector of string
std::map<int, std::string> mapExp = { {1, "first"}, {2, "second"}, {3, "third"}, {4,"fourth"} };
// vector of string to store the value type of map
std::vector<std::string> vValue;
// Convert function
std::transform(mapExp.begin(), mapExp.end(), std::back_inserter(vValue),
[](const std::pair<int, string> &mapItem)
{
return mapItem.second;
});
The other answers mention std::transform, and semantically it's the right choice. But in practice std::accumulate might fit better for this task, because:
it allows adding const to the resulting vector;
it just looks nicer, truly functional-style.
Example (using C++17 syntax):
#include <numeric> // for std::accumulate. Note that it's not in <algorithm> where std::transform is located, thanks to Anton Krug for pointing this out
auto map = std::map<int,bool>{};
map[0]=true;
map[1]=false;
const auto mapValues = std::accumulate(map.begin(), map.end(), std::vector<bool>(map.size()), [](auto& vector, const auto& mapEntry) {
vector.push_back(mapEntry.second);
return vector;
});
Surprised nobody has mentioned the most obvious solution, use the std::vector constructor.
template<typename K, typename V>
std::vector<std::pair<K,V>> mapToVector(const std::unordered_map<K,V> &map)
{
return std::vector<std::pair<K,V>>(map.begin(), map.end());
}