I need to compare one given value with a retrieved values. I do this several times in the code. I am not satisfied with how it looks and I am seeking for a some sort of an util
i like the collections approach, maybe use a hash_set instead of a vector. store the values in a property file and have a method to populat the hash_set from the file, and another one to return a boolean if the value is in the hash_set. then you can get down to one 2 lines in the main code.
Which changes more, the 'value' or the values returned by 'getValueX()'? You can insert everything into a hash_map/map and then do a search that way, as you've suggested with the containers.
you can write a set of template functions which will help you through with this, for example:
template <typename T>
bool InSet(const T & item, const T & i1, const T & i2) {
return item==i1 || item==i2;
}
template <typename T>
bool InSet(const T & item, const T & i1, const T & i2, const T & i3) {
return item==i1 || item==i2 || item==i3;
}
Note that you can make InSet to work like it took a variable number of arguments by creating multiple templates with different number of arguments.
And then:
int i;
if (InSet(i, 3, 4, 5)) { ... }
string s;
if (InSet(s, "foobar", "zap", "garblex")) { ... }
etc.
It depends on the source of the retrieved values, if you're reading in from a file or stream then you'd do something different but if your source is a series of functions then the following is a different way to do it, not perfect but may suit your needs:
const int count = 3;
std::string value = "world";
boost::function<std::string(void)> funcArray[count];
funcArray[0] = &getValue1;
funcArray[1] = &getValue2;
funcArray[2] = &getValue3;
for( int i = 0; i < count; ++i )
{
if( funcArray[i]() == value )
return 1;
}
If you know which functions are the source (as well as the count of objects) I expect you could assemble the function pointer array using the preprocessor.
You don't need a std::set or a std::vector. Just use std::set_intersection()...
Code is best...
#include <set>
#include <iostream>
#include <iterator>
using namespace std;
#define COUNT(TYPE,ARRAY) ( sizeof(ARRAY) / sizeof(TYPE) )
inline bool CaseInsensitiveCompare (const char * a, const char * b)
{ return strcasecmp( a, b ) < 0; }
int main()
{
const char * setA[] = { "the", "world", "is", "flat" };
const char * setB[] = { "the", "empty", "set", "is", "boring" };
stable_sort( setA, setA + COUNT( const char *, setA ),
CaseInsensitiveCompare );
stable_sort( setB, setB + COUNT( const char *, setB ),
CaseInsensitiveCompare );
cout << "Intersection of sets: ";
set_intersection( setA, setA + COUNT( const char *, setA ),
setB, setB + COUNT( const char *, setB ),
ostream_iterator<const char *>(cout, " "),
CaseInsensitiveCompare );
cout << endl << endl;
}
Or perhaps, given your 1-N lookup problem:
(Note: Use binary_search() AFTER sorting!)
if ( binary_search( setA, setA + COUNT( const char *, setA ),
"is", CaseInsensitiveCompare ) )
...
if ( binary_search( setA, setA + COUNT( const char *, setA ),
"set", CaseInsensitiveCompare ) )
...
If the values you're looking for are Comparable with operator< (like ints, float and std::strings), then it's faster to use an std::set to put the values there and then check set.find(value) == set.end(). This is because the set will store the values with a certain order that allows for faster lookups. Using an hash table will be even faster. However, for less than 50 values or so you might not notice any difference :) So my rule of thumb would be:
Less then 5 items: if with multiple ||
5 or more: put in a set or hash table