Reputation: 3
For example, I have defined the class foo and the vector vec:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class foo {
public:
foo(int flag, char ch):flag(flag), ch(ch) {}
int flag;
char ch;
};
int main(void)
{
vector<foo> vec;
vec.push_back(foo(1,'a'));
vec.push_back(foo(2,'b'));
vec.push_back(foo(3,'c'));
//blabla...
}
I've found how to find the single element: How to find an item in a std::vector?
But now I want to find an object by just giving a char, say, 'b'. How can I achieve this goal efficiently?
Upvotes: 0
Views: 121
Reputation: 12651
Define an implicit constructor for foo
using only char
as argument.
foo(char ch) : ch(ch), flag(int()) {
}
OR add default args to your existing constructor
foo(char ch, int flag = int()) : ch(ch), flag(flag) {
}
AND overload a comparison operator
bool operator ==(const char & rhs) {
return ch == rhs;
}
You can then use std::find
directly.
vector<foo>::iterator it = std::find(vec.begin(), vec.end(), 'b');
if (it != vec.end()) {
... // do something
}
A working code will then look like
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class foo {
public:
foo(char ch, int flag = int()) : flag(flag), ch(ch) {}
int flag;
char ch;
inline bool operator ==(const char & rhs) { return ch == rhs; }
};
int main(void) {
vector<foo> vec;
vec.push_back(('a', 1));
vec.push_back(('b', 2));
vec.push_back(('c', 3));
vector<foo>::iterator it = find(vec.begin(), vec.end(), 'b');
if (it != vec.end())
cout << "found" << endl;
return 0;
}
See http://ideone.com/ue907i demo.
Upvotes: 1
Reputation: 65770
You could use std::find_if
for this:
//c++14
std::find_if(std::begin(vec),std::end(vec),
[](auto&& v) { return v.ch == 'b'; })
//c++11
std::find_if(std::begin(vec),std::end(vec),
[](const foo& v) { return v.ch == 'b'; })
You could wrap this up in a function if you find yourself needing this pattern a number of times:
//c++14, c++11 version left as exercise
decltype(auto) find_foo (const std::vector<foo>& vec, char c)
{
return std::find_if(std::begin(vec),std::end(vec),
[c](auto&& v) { return v.ch == c; });
}
A better option might be to use a std::unordered_map<char,int>
instead of a std::vector<foo>
:
int main()
{
std::unordered_map<char,int> my_map;
my_map['a'] = 1;
my_map['b'] = 2;
my_map['c'] = 3;
cout << my_map['b']; //instead of that std::find_if nonsense
}
Upvotes: 6
Reputation: 311126
You can use standard algorithm std::find_if
declared in header <algorithm>
. For example
#include <iostream>
#include <algorithm>
class foo {
public:
foo(int flag, char ch):flag(flag), ch(ch) {}
int flag;
char ch;
};
int main()
{
std::vector<foo> vec;
vec.push_back(foo(1,'a'));
vec.push_back(foo(2,'b'));
vec.push_back(foo(3,'c'));
char ch = 'b';
auto it = std::find_if( vec.begin(), vec.end(),
[&]( const foo &f ) { return f.ch == ch; } );
if ( it != vec.end() ) std::cout << it->flag << ' ' << it->ch << std::endl;
}
If your compiler supports C++14 then the lambda expression can be written also the following way
auto it = std::find_if( vec.begin(), vec.end(),
[ch = 'b']( const foo &f ) { return f.ch == ch; } );
The other approach is to make the seach as an interface of the class itself. For example
class foo {
public:
foo(int flag, char ch):flag(flag), ch(ch) {}
int flag;
char ch;
class find_by_ch
{
public:
find_by_ch( char ch ) : ch( ch ) {}
bool operator ()( const foo &f ) const { return f.ch == ch; }
private:
char ch;
};
};
//...
auto it = std::find_if( vec.begin(), vec.end(), foo::find_by_ch( 'b' ) );
Upvotes: 2
Reputation: 506
If the vector is sorted (as in your example), you can use lower_bound for logarithmic performance. If the vector is not sorted, you can use find for linear performance.
Upvotes: 0