I have a vector of objects. My data structure is the following:
class my_class{
float a; int b;
};
my_class obj;
vector<my_class> vec;
The vector vec contains data of the form:
vec
((10.0,2),(100,3),(19.0,3)...)
Now from vector vec I intend to delete the elements which are less than or equal to the last element of vec...For this I am using erase and remove_if functions:
vec.erase(std::remove_if(vec.begin(), vec.end(), predicate_function(vec, (vec.end()-1).a, (vec.end()-1).b)), vec.end());
The predicate_function which I have does an iteration over "vec". However, this defeats the purpose of using std::remove_if. Can someone please help as to what the predicate_function should look like in order for remove_if to work. I dont want to use lambda_function. Also my compiler is GCC
The predicate function will automatically be passed the parameters from each Iterator. So it'd look something like:
bool predicate_function(const my_class& m)
{
//Some logic here
}
Which would then simply be called as:
vec.erase(std::remove_if(vec.begin(), vec.end(), predicate_function), vec.end());
In C++ terms, std::remove_if expects a UnaryPredicate as its 3rd parameter, which is either a function or functor accepting 1 argument and returning bool.
Edit: To do what you want in the comment, you'd need to use a functor (or std::bind, but we'll go the functor route here):
struct compare_last
{
const my_class last_;
compare_last(const my_class& last)
: last_(last)
{ }
bool operator()(const my_class& m) const
{
return m == last_; //Or however you do your comparisons
}
};
my_class& last = *(--vec.end());
vec.erase(std::remove_if(vec.begin(), vec.end(), compare_last(last)), vec.end());
Related
I'm trying to figure out a nice way to find the index of a certain object in a vector - by comparing a string to a member field in the object.
Like this:
find(vector.begin(), vector.end(), [object where obj.getName() == myString])
I have searched without success - maybe I don't fully understand what to look for.
You can use std::find_if with a suitable functor. In this example, a C++11 lambda is used:
std::vector<Type> v = ....;
std::string myString = ....;
auto it = find_if(v.begin(), v.end(), [&myString](const Type& obj) {return obj.getName() == myString;})
if (it != v.end())
{
// found element. it is an iterator to the first matching element.
// if you really need the index, you can also get it:
auto index = std::distance(v.begin(), it);
}
If you have no C++11 lambda support, a functor would work:
struct MatchString
{
MatchString(const std::string& s) : s_(s) {}
bool operator()(const Type& obj) const
{
return obj.getName() == s_;
}
private:
const std::string& s_;
};
Here, MatchString is a type whose instances are callable with a single Type object, and return a boolean. For example,
Type t("Foo"); // assume this means t.getName() is "Foo"
MatchString m("Foo");
bool b = m(t); // b is true
then you can pass an instance to std::find
std::vector<Type>::iterator it = find_if(v.begin(), v.end(), MatchString(myString));
In addition to the Lambda and the handwritten functor used by juancho, you have the possibility to use boost::bind (C++03) or std::bind (C++11) and a simple function:
bool isNameOfObj(const std::string& s, const Type& obj)
{ return obj.getName() == s; }
//...
std::vector<Type>::iterator it = find_if(v.begin(), v.end(),
boost::bind(&isNameOfObj, myString, boost::placeholders::_1));
Or, if Type has a method isName:
std::vector<Type>::iterator it = find_if(v.begin(), v.end(),
boost::bind(&Type::isName, boost::placeholders::_1, myString));
This is just for completeness. In C++11 I'd prefer Lambdas, in C++03 I'd use bind only if the comparison function itself exists already. If not, prefer the functor.
PS: Since C++11 has no polymorphic/templated lambdas, bind still has it's place in C++11, e.g. if the parameter types are unknown, hard to spell, or otherwise not easy to deduce.
A simple iterator may help.
typedef std::vector<MyDataType> MyDataTypeList;
// MyDataType findIt should have been defined and assigned
MyDataTypeList m_MyObjects;
//By this time, the push_back() calls should have happened
MyDataTypeList::iterator itr = m_MyObjects.begin();
while (itr != m_MyObjects.end())
{
if(m_MyObjects[*itr] == findIt) // any other comparator you may want to use
// do what ever you like
}
I am trying to find an object in a vector of objects whos value of a member variable is true. Could it be done without defining a lamba function or function object, by just specifying the member variable itself:
class A
{
public:
explicit A(bool v, int v2, float v3) : value(v), value2(v2), value3(v3)
{}
...
bool value;
int value2;
float value2;
...
}
int main()
{
std::vector<A> v;
v.push_back(A(false, 1, 1.0));
v.push_back(A(true, 2, 2.0));
v.push_back(A(false, 3, 3.0));
auto iter = std::find_if(v.begin(), v.end(), &A::value);
}
Compiling as is above does not work as it assumes a A* and not A.
Not that its a problem to use lambdas, just curious.
You may use std::mem_fn
auto iter = std::find_if(v.begin(), v.end(), std::mem_fn(&A::value));
Demo
Note that range library should allow directly:
auto iter = range::find_if(v, &A::value);
If you cannot use C++11 lambdas, you can do that with std::bind:
auto iter = std::find_if(v.begin(), v.end(), std::bind(&A::value, std::placeholders::_1));
A solution could be the following
(Optional) Don't mark your constructor A(bool) as explicit to allow implicit conversion from bool to A (live demo on coliru)
Overload operator==() so that it only uses value to establish equality.
You can also supply an operator==(bool v) { return value == v;} (see this demo)
Of course I would advise you not to use that solution as it is quite dirty. Just supply a predicate using std::find_if to do the job. Note that the said predicate must have an operator() so of course you cannot supply a value such as a bool as the predicate to std::find_if
I'm trying to write a function to sort a vector of custom class objects by a variety of different attributes.
The c++ sort reference, found here:
http://www.cplusplus.com/reference/algorithm/sort/
Says that you can sort like this:
std::sort (myvector.begin(), myvector.end(), myfunction);
What I would like to be able to do is pass an argument to myfunction in addition to the two objects from my vector like this:
std::sort (myvector.begin(), myvector.end(), myfunction(mode=7));
Do you know of a way to do so?
I am relatively new to c++, coming from python where this would be easy.
If you are using C++11, you can use a lambda:
sort(myvec.begin(), myvec.end(), [] (Type a, Type b) { return myfunction(a,b,7); });
You can use a functor instead of a free function:
struct Functor{
int mode;
bool operator() (int a,int b) { return (a<b);}
} functor;
The overloaded () operator executes when the functor is called by sort. In there you can have a variable mode and use it as you need.
Then set mode (you could also set in on the functor constructor) and call sort using it:
functor.mode = 7; // or set it in the constructor
std::sort (myvector.begin(), myvector.end(), functor);
Create a functor:
struct MyFunction {
bool operator()(const T& lhs, const T& rhs) const { /* implement logic here */ }
int mode;
};
Then pass an instance of that instead of your plain function myfunction. Here, T is the type used to instantiate your std::vector.
MyFunction f;
f.mode = 7;
std::sort (myvector.begin(), myvector.end(), f);
If you have C++11 support, you can use a lambda function:
std::sort(myvector.begin(), myvector.end(), [](const T&a, const T& b) { /* implement*/ });
I know how does heap work and how it arranges min and max elements. It is easy, if vector contains only int, to apply make_heap in STL. But how to apply make_heap() if vector contains structure of string and int. Iwant to make heap based on int value in structure.
Please tell me how to do that.
You have to provide comparison function for your structure:
struct A
{
int x, y;
};
struct Comp
{
bool operator()(const A& s1, const A& s2)
{
return s1.x < s2.x && s1.y == s2.y;
}
};
std::vector<A> vec;
std::make_heap(vec.begin(), vec.end(), Comp());
Yes, you can use std::make_heap with std::pair<int, std::string> directly because std::pair has the required less-than comparison operator<. There is even an example in the reference linked above using that particular instantiation of std::pair.
when i'm deleting from a non-nested container like a vector, i'm doing something like:
struct is_to_remove
{
is_to_remove(dynamic_bitset<>& x) : x(x) {}
const bool operator()(unsigned int id)
{
return x[id];
}
private:
dynamic_bitset<> x;
};
inline static void remove_elements_in_vector(vector<unsigned int>& vec, boost::dynamic_bitset<>& to_remove)
{
// use the erase-remove idiom to remove all elements marked in bitset
vec.erase( remove_if(vec.begin(), vec.end(), is_to_remove(to_remove)), vec.end() );
}
That is the so called erase-remove idiom.
Now, i have a second data strucurevector<vector<unsigned int> > or deque<vector<unsigned int> >, where i want to delete the outer container elements (which is itself a container of the inner type) according to a bitset.
Is it possible to use the erase-remove idiom on this nested container types?
If it is, how is it possible?
Are there restrictions? (like: vec of vec is possible, but not deque of vec)?
My first and naive approach was the following. I assumed that remove_if is iterating sequentially and in order over the elements and deciding one after the other. Is that a wrong assumption?
struct is_to_remove_new
{
is_to_remove_new(dynamic_bitset<>& x, unsigned int index) : x(x), index(index) {}
const bool operator()(vector<unsigned int> & vec)
{
return x[index++];
}
private:
dynamic_bitset<> x;
unsigned int index;
};
inline static void remove_elements_in_vectorvector(vector<vector<unsigned int> >& vec, boost::dynamic_bitset<>& to_remove)
{
// use the erase-remove idiom to remove all elements marked in bitset
vec.erase( remove_if(vec.begin(), vec.end(), is_to_remove_new(to_remove, 0)), vec.end() );
}
The result is wrong, therefore i'm looking for a correct solution here. I suppose i assumed some things, which aren't guaranteed. For me, the base question is the following: How to get the identity of the inner container for checking if it is to remove..
My naive approach posted above just counts and assumes a sequential processing.
Thanks for your help.
Sascha
Update and Warning
For a vector o vectors, Stas solution is working great. But i think this solution will not work for a deque of vectors because a deque isn't saved in a contiguous way. This means, that the calculation of the index in the functor fails.
Can anyone verify that?
It doesn't matter which elements are in the vector. If you define which of them should be removed, they will be removed.
As you said, the question is how to identify an element in a vector. The most obvious answer is by its index [0; vector_size - 1].
Thanks to a vector, you can easily get an element index, by the element itself.
std::vector<std::string> vec;
vec.push_back("zero");
vec.push_back("one");
vec.push_back("two");
std::string& elem = vec[2];
int index = std::distance(&vec[0], &elem); // get element index by element itself
// index == 2
So, you can easily identify vector elements by indices inside remove_if algorithm predicate. Take a look at the following example. It is pretty silly and use hard-coded std::bitset<6>, but this is just an illustration:
#include <vector>
#include <string>
#include <bitset>
struct ToRemove
{
ToRemove(std::vector<std::string>& vec, const std::string& mask)
: m_vec(vec)
, m_mask(mask)
{}
bool operator()(std::string& obj)
{
const int index = std::distance(&m_vec[0], &obj);
return m_mask[index];
}
std::vector<std::string>& m_vec;
std::bitset<6> m_mask;
};
Usage
int main (int argc, char const *argv[])
{
std::vector<std::string> vec;
vec.push_back("zero");
vec.push_back("one");
vec.push_back("two");
vec.push_back("three");
vec.push_back("four");
vec.push_back("five");
std::string mask = ("010011"); // Remove "zero", "one" and "four"
vec.erase(remove_if(vec.begin(), vec.end(), ToRemove(vec, mask)), vec.end());
for (unsigned i = 0; i < vec.size(); ++i)
{
std::cout << vec[i] << " ";
}
std::cout << std::endl;
return 0;
}
Result
two three five