I want to search for a value in two std::vector
's. If it was found in one of them I want to return its iterator. If not, I want to return some value which indicates that it was not found.
In normal situation where only one std::vector
is involved, I would return std::vector::end
. What should I do in this situation?
Normal situation:
auto find_ten=[](const std::vector<int>& v){
return std::find(v.cbegin(),v.cend(),10);
}
My situation:
auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){
auto it1=std::find(v1.cbegin(),v1.cend(),10);
if(it1==v1.cend()){
auto it2=std::find(v2.cbegin(),v2.cend(),10);
if(it2==v2.cend()){
//What should I return here??
}
return it2;
}
return it1;
}
I want to return something that I can check it later to know that the number 10
was not found in any of them.
Since C++14 you are allowed to compare value-initialized iterators if they meet the ForwardIterator category or stronger (see [forward.iterators] paragraph 2). A value-initialized iterator is the equivalent of a null pointer, so you can use:
if(it2==v2.cend()){
return std::vector<int>::iterator{};
}
And then the caller can do:
std::vector<int>::iterator not_found{};
auto find_ten = ...
if (find_ten != not_found)
{
...
}
auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){
auto it1=std::find(v1.cbegin(),v1.cend(),10);
if(it1==v1.cend()){
auto it2=std::find(v2.cbegin(),v2.cend(),10);
return it2; // whether it's end or not
}
return it1;
}
when using, just test (rval != v2.end())
(rval is the returned iterator). I know, that's not very symmetric.
OR
Pass a boolean as out
parameter
auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2, bool &found){
found = true; // suppose we will find it
auto it1=std::find(v1.cbegin(),v1.cend(),10);
if(it1==v1.cend()){
auto it2=std::find(v2.cbegin(),v2.cend(),10);
found = it2 != v2.end(); // false if not in v1 or in v2
return it2; // whether it's end or not
}
return it1;
}
You could simply return the right-most vector's end iterator, this makes logical sense:
auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){
auto it1=std::find(v1.cbegin(),v1.cend(),10);
if(it1==v1.cend()){
return std::find(v2.cbegin(),v2.cend(),10);
}
return it1;
}
auto it = find_ten(v1, v2);
if (it == v2.end()) // no luck
Or you could take an iterator argument:
auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2, std::vector<int>::iterator endit){
auto it1=std::find(v1.cbegin(),v1.cend(),10);
if(it1==v1.cend()){
auto it2=std::find(v2.cbegin(),v2.cend(),10);
if(it2==v2.cend()){
return endit;
}
return it2;
}
return it1;
}
These both, of course, depend on your use case: if you're going to use the returned iterator for more than just direct access to an element, you'll need to consider a different approach:
--- EDIT ---
If you need to use the iterator beyond just direct access to the offending element, you could use std::reference_wrapper
to let you return a reference to the offending vector (or you could just return a pointer).
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using find_ten_t = std::pair<std::reference_wrapper<const std::vector<int>>, std::vector<int>::const_iterator>;
auto find_ten = [](const std::vector<int>& v1, const std::vector<int>& v2) -> find_ten_t {
auto it1 = std::find(v1.cbegin(), v1.cend(), 10);
if (it1 != v1.cend()) {
return std::make_pair(std::ref(v1), it1);
}
auto it2 = std::find(v2.cbegin(), v2.cend(), 10);
return std::make_pair(std::cref(v2), it2);
};
int main() {
std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 3, 4, 10 };
auto r = find_ten(v1, v2);
std::cout << "r.first[0] = " << r.first.get()[0] << "\n";
}
Live demo: http://ideone.com/cNLJKg
Not really brilliant, I suppose, but... I propose returning a std::pair
where the first element is an int (0 for "not found", 1 for "found in first" and 2 for "found in second") and the second is the iterator.
Something like
auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){
auto it1=std::find(v1.cbegin(),v1.cend(),10);
if(it1==v1.cend()){
auto it2=std::find(v2.cbegin(),v2.cend(),10);
if(it2==v2.cend()){
return std::make_pair(0, v1.cend()); // or make_pair(0, v2.cend())
}
return std::make_pair(2, it2);
}
return std::make_pair(1, it1);
};
Or better: you could return a pair of iterator where the second is the cend()
of the corresponding vector; something like
auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){
auto it1=std::find(v1.cbegin(),v1.cend(),10);
if(it1==v1.cend()){
return std::make_pair(std::find(v2.cbegin(),v2.cend(),10), v2.cend());
}
return std::make_pair(it1, v1.cend());
};
I think it's important to return the cend()
correspindig iterator because I suppose you want to use the iterator pointing to 10 and you could iterate it.
Obvioulsy, If you're only interested in knowing if 10 is present in v1
or in v2
, I suppose you should returning a bool
: true
for "found", false
otherwise; something like
auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){
auto ret = v1.cend() != std::find(v1.cbegin(),v1.cend(),10);
if ( ret == false )
ret = v2.cend() != std::find(v2.cbegin(),v2.cend(),10);
return ret;
};
p.s.: sorry for my bad English.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With