If you’re a beginner C++ developer, you have probably tried finding elements by writing a complicated raw loop or something similar. In this post, we look at how to use std::find_if(...)
to find elements in C++ arrays, vectors, lists and maps.
Due to its flexibility, std::find_if
works for all C++ collections and it’s also very easy to use.
The list below shows the contents of this post.
- Learning
std::find_if
with a video example! - Creating an
std::array
to hold our data. - Using
std::find_if
to get the element iterator.- Explaining inputs to
std::find_if
. - Check if element was found.
- Using the “found” iterator.
- Explaining inputs to
Video – Finding Items In C++ Collections
For demonstration purposes, I’ve posted the video below. Hopefully, you can learn by example how to find items in C++ elements in collections.
If you have any questions regarding the things taught in the video, feel free to either comment below or on the video itself. If you really want to help me out, please subscribe to the channel!
Creating The Collections To Hold Our Data
Interestingly enough, we need an actual collection (vectors, array, lists, etc) to actually find items! Therefore, we’re simply setting the context in this section by creating an array.
The code block below includes the necessary headers for this post, as well as the definitions of a custom struct
and the array holding the information we will later on “find”.
#include <algorithm>
#include <array>
#include <cstdio>
#include <string>
#include <string_view>
struct Person
{
float height;
int age;
std::string_view name;
};
static constexpr std::array<Person, 8> people {{
{1.7f, 24, "matheus"},
{1.9f, 22, "lucas"},
{1.63f, 27, "linda"},
{1.98f, 41, "kobe"},
{1.82f, 41, "jake"},
{1.65f, 37, "jena"},
{1.78f, 57, "patrick"},
{1.63f, 47, "drew"}
}};
To summarise, the list below explains why each header was imported.
algorithm
containstd::find_if
and other very useful functions in the C++ standard.array
defines thestd::array
collection, which we use above to store our “people” information.cstdio
definesputs(...)
, which we use for printouts later on in this post.string
brings thestd::string
collection, as well as thestd::to_string(...)
functions we later use in this post.string_view
is used to store c-strings in nice, manageable collections.
How And Why Is Our Data Being Stored In Arrays?
As you can see in the cost above, we defined the struct Person
, which simply stored the height, age and name of a hypothetical person.
Following that, we create the std::array<...> people
to store multiple persons information.
Long story short, there’s no particular reason for using std::array<...>
, other than having my data fully available at compile time. Furthermore, as long as you have a collection of data stored in a C++ standard collection (such as vector and lists), this post will work for you.
There are certain reasons for using std::array<...>
to store data in certain situations, such as converting and storing files as C++ byte arrays in your code.
Using std::find_if To Find Items In C++ Arrays / Collections
Without further ado, let’s learn how to call std::find_if
. The code bock below shows a program that finds the input name in out people
array.
int main(int argc, char** argv)
{
if (argc <= 1)
{
return -1;
}
const std::string_view to_find = argv[1];
const auto found = std::find_if(begin(people),
end(people),
[&](const auto& input){
return input.name == to_find;
});
if (found == end(people))
{
// This means the item wasn't found!
puts("Item was not in the collection");
return -1;
}
// Do whatever with "found"
}
Briefly speaking, the following list explains what the code does.
- Makes sure there’s at least one argument being passed to the program.
- Stores the first argument as the name we’ll be using to find in the list.
- Calls
std::find_if
, storing the result infound
. - Checks whether the element was found.
Explaining The Inputs To std::find_if
As you can see, std::find_if
takes three inputs: the beginning iterator, the end iterator, and the predicate (function) used to check each and every element.
If you don’t understand what “iterators” are, don’t worry too much. For the purposes of this tutorial, they are something that “points” to an element in the list, kind of like a pointer. Hence, “beginning iterator” means the first element to check. On the other hand, “end iterator” means the end of your list, or where to stop the search.
In addition, the last argument to std::find_if
is a function taking an element from the list, and returning either true
or false
. If the function returns true, it means the element was found, if it returns false, the element was not yet found, and the search will continue.
To make it clear, the “predicate” argument to std::find_if
is a callable object, meaning either a function, functor, or lambda taking one argument that is the same type stored in your list. Moreover, this predicate will be called for each element in your list, with the element being passed as the argument. This is essentially what std::find_if(...)
does internally.
Checking If The Element Was Found In Arrays
As previously mentioned, std::find_if(...)
returns an iterator for the collection you’re searching. If you don’t know much about iterators, notice that they can sometimes be “invalid”.
In the context of std::find_if(...)
, valid iterators point to actual elements of your list, and invalid iterators don’t point to any valid elements. More specifically, invalid iterators will point to end(collection)
, or the end iterator of a collection (this is not the last item).
For this reason, the branch in lines 16-21 of the previous code block show how to “check” if the element was found. In other words, if the iterator returned is end(people)
, then the element was not found.
Using The Found Element
Now that you know how to check if the element was found, let’s actually use the information we found. Needless to say, the variable found
should point to an element of the list if it’s valid.
auto const position = std::distance(begin(people), found);
puts("Found at position");
puts(std::to_string(position).c_str());
puts("Name is");
puts(found->name.data());
puts("Age is");
puts(std::to_string(found->age).c_str());
puts("Height is");
puts(std::to_string(found->height).c_str());
The code block above shows how to use the found
iterator to print out all the information about the found element. Note that the syntax is pretty much the same as a pointer!
Therefore, if you add the above code to our previousmain()
function, just after the found
check, the program should now print the name, height and age of the found person.
As a last note, if you would like to find_if out more about the std::find(...)
, std::find_if(...)
, and std::find_if_not(...)
functions provided by the algorithm
header, check out the C++ documentation on the find functions!
Have I missed anything? Spotted any mistakes? Do you have suggestions or feedback? Feel free to comment below and I’ll reply as soon as possible!
Be First to Comment