Counting element properties in a vector - c++

I have a vector of objects, and I'd like to count how many of them contain a certain property.
I'm fairly sure this can be done with the STL but I couldn't find an example. I could of course use a loop and count myself, but I need to do this many times and I'd prefer a concise way of doing this.
I'm looking to do something like the pseudo code below
class MyObj {
public:
std::string name;
}
std::vector<MyObj> objects
int calledJohn = count(objects,this->name,"jonn")

If you're looking to count how many objects have a certain property, std::count_if is the way to go. std::count_if takes a range to iterate over and the functor object that will determine if the object has the value:
auto calledJohn = std::count_if(std::begin(objects), std::end(objects),
[] (const MyObj& obj) { return obj.name == "John"; });

Use std::count_if
auto n = std::count_if(objects.begin(), objects.end(),
[](const MyObj& o) { return o.name == "jonn";});

There is a function std::count_if in the algorithm header that does exactly that for you. You have to provide an iterator range (so in your case objects.begin and objects.end) and a predicate that could be a lambda function or any other callable object:
auto number = std::count_if(objects.begin(), objects.end(), [](const MyObj &object){if(/*your condition*/){return true;}});

Related

constructing a std::vector using std::transform. Possibility to return unnamed result?

Let's have
class InputClass;
class OutputClass;
OutputClass const In2Out(InputClass const &in)
{
//conversion implemented
}
and finally
std::vector<OutputClass> Convert(std::vector<InputClass> const &input)
{
std::vector<OutputClass> res;
res.reserve(input.size());
//either
for (auto const &in : input)
res.emplace_back(In2Out(in));
return res;
//or something like
std::transform(input.begin(), input.end(), std::back_inserter(res), [](InputClass const &in){return In2Out(in);});
return res;
}
And now my question:
Can I rewrite the Convert function somehow avoiding the need to name the new container? I. e. is there a way to construct a vector directly using something roughly like std::transform or std::for_each?
As in (pseudocode, this unsurprisingly does not work or even build)
std::vector<OutputClass> Convert(std::vector<InputClass> const &input)
{
return std::transform(input.begin(), input.end(), std::back_inserter(std::vector<OutputClass>()), [](InputClass const &in){return In2Out(in);});
}
Searched, but did not find any elegant solution. Thanks!
Starting in C++ 20 you can use the new std::ranges::transform_view to accomplish what you want. It will call your transformation function for each element in the container that it is adapting and you can use that view to invoke std::vector's iterator range constructor which will allocate the memory for the entire vector once and then populate the elements. It still requires you to create a variable in the function but it becomes much more streamlined. That would give you something like
std::vector<OutputClass> Convert(std::vector<InputClass> const &input)
{
auto range = std::ranges::transform_view(input, In2Out);
return {range.begin(), range.end()};
}
Do note that this should optimize to the exact same code your function generates.
Yes it is possible, and quite simple when using boost:
struct A
{
};
struct B
{
};
std::vector<B> Convert(const std::vector<A> &input)
{
auto trans = [](const A&) { return B{}; };
return { boost::make_transform_iterator(input.begin(), trans), boost::make_transform_iterator(input.end(), trans) };
}
https://wandbox.org/permlink/ZSqt2SbsHeY8V0mt
But as other mentioned this is weird and doesn't provide any gain (no performance gain or readability gain)
Can I rewrite the Convert function somehow avoiding the need to name the new container?
Not using just std::transform. std::transform itself never creates a container. It only inserts elements to an output iterator. And in order to both get output iterator to a container, and return the container later, you pretty much need a name (unless you allocate the container dynamically, which would be silly and inefficient).
You can of course write a function that uses std::transform, creates the (named) vector, and returns it. Then caller of that function doesn't need to care about that name. In fact, that's pretty much what your function Convert is.

How to use lambda for std::find_if

I am trying to use std::find_if to find an object that matches some criteria. Consider the following:
struct MyStruct
{
MyStruct(const int & id) : m_id(id) {}
int m_id;
};
...
std::vector<MyStruct> myVector; //... assume it contains things
MyStruct toFind(1);
std::vector<MyStruct>::iterator i = std::find_if(myVector.begin(), myVector.end(), ???);
I am not sure what to put in the ???
All the examples I have seen have a lambda that uses a hard-coded value to check for the ID. What I want is to return the iterator/success only if the id of toFind matches the id of one of the items in the vector.
All the examples I have see don't show me how to pass the two parameters
EDIT
Additional info
There are two different scenarios I have to use this for
One in which there is an == operator for the struct
and another in which there is no operator == for the struct - and i can't create one because the criteria for finding a match for this scenario is not as rigid as would be used for an equivalence operator.
(And thanks to all who responded; I was able to use find() in one case and with your help was able to use find_if() for the other)
Try this:
std::find_if(
myVector.begin(), myVector.end(),
[&toFind](const MyStruct& x) { return x.m_id == toFind.m_id;});
Alternatively, if you had defined an appropriate == overload for MyStruct, you could just use find:
std::find(myVector.begin(), myVector.end(), toFind); // requires ==
The find_if version is usually best when you have some kind of heterogeneous lookup, for example if you were just given an int, not a value of MyStruct.
This is where the lambda capture comes into play. Besides saying what type of parameters are to be passed to the lambda you can also say what existing variables are to be used to construct the lambda with. So in this case you would have something like
std::vector<MyStruct>::iterator i = std::find_if(myVector.begin(),
myVector.end(),
[&](const auto& val){ return val.m_id == toFind.m_id; } );
So the [&] says capture all variables used in the body of the lambda by reference. The (const auto& val) makes the operator() of the lambda a template and lets you take in any type. Then in the body we compare what is passed in from find_if to toFind.
You may use the following:
MyStruct toFind(1);
std::vector<MyStruct>::iterator i =
std::find_if(myVector.begin(), myVector.end(),
[&](const auto& e) { return e.id == toFind.id; });
Do as following:
std::find_if(myVector.begin(), myVector.end(),
[&toFind] (const auto &ele) { return ele.m_id == toFind.m_id}; );

Avoiding Helper Functions for Doing Comparisons

Say I have a type with a member function:
class Thing {
std::string m_name;
public:
std::string & getName() {
return m_name;
}
};
And say I have a collection of that type:
std::vector<Thing> things;
And I want to keep the things in order by name. To do that, I use std::lower_bound to figure out where to put it:
bool thingLessThan(Thing const& thing, std::string const& name) {
return thing.getName() < name;
}
void addThing(std::string const& name) {
vector<Thing>::iterator position = lower_bound(
things.begin(), things.end(),
name,
thingLessThan);
if (position == things.end() || position->getName() != name) {
position = things.insert(position, Thing());
position->getName() = name;
}
}
Is there a way to do the same thing as the thingLessThan function without actually creating a function, perhaps using std::mem_fun, std::less, etc?
Other than a lambda you can simply define an operator< which adheres to strict weak ordering to allow a container of your object to be comparable by STL algorithms with the default predicate std::less
class whatever
{
public:
bool operator<(const whatever& rhs) const { return x < rhs.x; }
private:
int x;
};
std::vector<whatever> v;
std::sort(v.begin(), v.end());
Sure. You can use a lambda expression (assuming your compiler supports it):
vector<Thing>::iterator position = lower_bound(
things.begin(), things.end(),
name,
[](Thing const& thing, std::string const& name) { return thing.getName() < name; });
Of course, an alternative option is just to define operator< for the class, then it will be used by default, if you don't specify another comparer function for std::lower_bound.
Depending on what your purpose is? If you just like the syntactic niceness of not declaring something to be used in one place, use lambda expressions to create an anonymous function.
You can overload operator<() and use std::less<T> if you don't want to write predicates contantly. Also you can use lambda-expressions, which would be much nicer, because operator<() is logically connected only with things, that can be put in some order in obvious ways, like numbers or strings.
If you use a std::map, the strings will be placed in alphabetical order automatically. If you want to modify the ordering further, create your own key comparison function. I think this would be the simplest option.
To use a std::list, you can write your own comparison code inside of the addThing() function that goes through the list looking at each string and inserts the new one at the appropriate place.

C++ remove_if on a vector of objects

I have a vector (order is important) of objects (lets call them myobj class) where I'm trying to delete multiple objects at a time.
class vectorList
{
vector<*myobj> myList;
};
class myobj
{
char* myName;
int index;
bool m_bMarkedDelete;
}
I was thinking that the best way to do this would be to mark specific myobj objects for deletion and then call myList.remove_if() on the vector. However, I'm not exactly sure how to use predicates and such for this. Should I create a member variable in the object which allows me to say that I want to delete the myobj and then create a predicate which checks to see if the member variable was set?
How do I implement the predicate as a part of the vectorList class?
Should I create a member variable in the object which allows me to say
that I want to delete the myobj and then create a predicate which
checks to see if the member variable was set?
Haven't you already done that? Isn't that what m_bMarkedDelete is for? You would write the predicate like this:
bool IsMarkedToDelete(const myobj & o)
{
return o.m_bMarkedDelete;
}
Then:
myList.erase(
std::remove_if(myList.begin(), myList.end(), IsMarkedToDelete),
myList.end());
Or, using lambdas:
myList.erase(
std::remove_if(myList.begin(), myList.end(),
[](const myobj & o) { return o.m_bMarkedDelete; }),
myList.end());
If your class doesn't actually have that member, and you're asking us if it should, then I would say no. What criteria did you use to decide to mark it for deletion? Use that same criteria in your predicate, for example:
bool IndexGreaterThanTen(const myobj & o)
{
return o.index > 10;
}
note -- The functions I've written are of course invalid since all your members are private. So you'll need some way to access them.
A predicate is basically a conditional comparison. It can be a function or object. Here's an example using new C++ lambdas. This code will go through the vector and remove the values equal to 3.
int arg[6] = {1, 2, 3, 3, 3, 5};
std::vector<int> vec(arg, arg+6);
vec.erase(
std::remove_if(
vec.begin(), vec.end(),
[](int i){ return i == 3;}),
vec.end());
Edit: For pointers let's say you had a vector or interfaces you could set them to nullptr then remove them in a batch with pretty much the same code. In VS2008 you won't have lambdas so make a comparison predicate function or struct instead.
bool ShouldDelete(IAbstractBase* i)
{
return i == nullptr;
// you can put whatever you want here like:
// return i->m_bMarkedDelete;
}
std::vector<IAbstractBase*> vec;
vec.erase(
std::remove_if(
vec.begin(), vec.end(),
ShouldDelete),
vec.end());

Find array element by member value - what are "for" loop/std::map/Compare/for_each alternatives?

Example routine:
const Armature* SceneFile::findArmature(const Str& name){
for (int i = 0; i < (int)armatures.size(); i++)
if (name == armatures[i].name)
return &armatures[i];
return 0;
}
Routine's purpose is (obviously) to find a value within an array of elements, based on element's member variable, where comparing member variable with external "key" is search criteria.
One way to do it is to iterate through array in loop. Another is to use some kind of "map" class (std::map, some kind of vector sorted values + binarySearch, etc, etc). It is also possible to make a class for std::find or for std::for_each and use it to "wrap" the iteration loop.
What are other ways to do that?
I'm looking for alternative ways/techniques to extract the required element.
Ideally - I'm looking for a language construct, or a template "combo", or a programming pattern I don't know of that would collapse entire loop or entire function into one statement. Preferably using standard C++/STL features (no C++0x, until it becomes a new standard) AND without having to write additional helper classes (i.e. if helper classes exist, they should be generated from existing templates).
I.e. something like std::find where comparison is based on class member variable, and a variable is extracted using standard template function, or if variable (the one compared against "key"("name")) in example can be selected as parameter.
The purpose of the question is to discover/find language feature/programming technique I don't know yet. I suspect that there may be an applicable construct/tempalte/function/technique similar to for_each, and knowing this technique may be useful. Which is the main reason for asking.
Ideas?
If you have access to Boost or another tr1 implementation, you can use bind to do this:
const Armature * SceneFile::findArmature(const char * name) {
find_if(armatures.begin(), armatures.end(),
bind(_stricmp, name, bind(&string::c_str, bind(&Armature::name, _1))) == 0);
}
Caveat: I suspect many would admit that this is shorter, but claim it fails on the more elegant/simpler criteria.
Sure looks like a case for std::find_if -- as the predicate, you could use e.g. a suitable bind1st. I'm reluctant to say more as this smacks of homework a lot...;-).
Why 5 lines? Clean doesn't have a number attached to it. In fact, clean code might take more lines in the utility classes, which can then be reused over and over. Don't restrict yourself unnecessarily.
class by_name
{
public:
by_name(const std::string& pName) :
mName(pName)
{}
template <typename T>
bool operator()(const T& pX)
{
return pX.name == pName;
}
private:
std::string mName;
};
Then:
const Armature* SceneFile::findArmature(const char* name)
{
// whatever the iterator type name is
auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
return iter == armatures.end() ? 0 : &(*iter);
}
Within restriction:
class by_name { public: by_name(const std::string& pName) : mName(pName) {} template <typename T> bool operator()(const T& pX) { return pX.name == pName; } private: std::string mName; };
Then:
const Armature* SceneFile::findArmature(const char* name)
{
// whatever the iterator type name is
auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
return iter == armatures.end() ? 0 : &(*iter);
}
:)
C++0x has ranged-based for-loops, which I think would make the most elegant solution:
const Armature* SceneFile::findArmature(const std::string& pName) const
{
for (auto a : armatures)
{
if (a.name = pName) return &a;
}
return 0;
}
You would probably need to use STL map. It gives you possibility to get the element using keys. Your key would be the name of armature.
http://www.cplusplus.com/reference/stl/map/
EDIT: :D
one liner B-)
const Armature* SceneFile::findArmature(const Str& name){for (int i = 0; i < (int)armatures.size(); i++) if(name == armatures[i].name) return &armatures[i]; return 0;}
Holy shiz, you're using _stricmp? FAIL. Also, you didn't actually tell us the type of the vectors or any of the variables involved, so this is just guesswork.
const Armature* SceneFile::findArmature(const std::string& lols) {
for(auto it = armatures.begin(); it != armatures.end(); it++) {
if (boost::iequals(lols, (*it).name))
return &(*it);
return NULL;
}
Ultimately, if you need this, you should put the armatures or pointers to them in a std::map. A vector is the wrong container if you're searching into it, they're best for when the collection is what's important rather than any finding behaviour.
Edited to use a std::string reference.