I have a problem that requires me to count the number of instances within this array that uses either std::count() or std::find(). I'm aware of how to do this using a standard data (see bottom code) type but not with the NameContainer that I'm using.
//Type
struct NameContainer{
char name [32];
}
//An array of containers
NameContainer *_storedNames = new NameContainer[_numberOfNames];
//An example of what I'm trying to do with a string rather than the NameContainer
std::vector<string> v(_storedNames, _storedNames + _numberOfNames);
//returns an numeric value
return std::count(v.begin(), v.end(), nameToSearch))
You can use a functor
struct names_equal {
string comp_to;
names_equal(string a) : comp_to(a) {}
bool operator()(NameContainer& p) {
return p.name == comp_to;
}
};
And count like
cout << std::count_if(v.begin(), v.end(), names_equal(nameToSearch));
This way nameToSearch doesn't have to be hard coded.
EDIT
If you can not use count_if, and has to be count then modify NameContainer and overload == for it.
struct NameContainer{
string name;
bool operator==(string str) {
return name == str;
}
};
Then count like this
cout << std::count(v.begin(), v.end(), nameToSearch);
you can use count_if and you provide a predicate (Unary function that accepts an element in the range as argument, and returns a value convertible to bool)
for example
bool myPred(NameContainer n){
return (strcmp(n.name, "name") == 0); }
std::vector<NameContainer> v(_storedNames, _storedNames + _numberOfNames);
int i=std::count_if(v.begin(), v.end(), myPred))
you can use strcmp() to compare character arrays.
if using only std::count or std::find:
both count and find takes the same type argument to compare as the type of conatainer, in your case NameContainer. std::count will execute following to compare searched values:
if (*first == val)
what means you have to overload operator== taking your class as arguments.
inline bool operator == (const NameContainer &first,const NameContainer &second){
return (strcmp(first.name,second.name)==0);
}
and then call std::count(v.begin(), v.end(), myObjectPredicate))
with myObjectPredicate being your NameContainer class object with name to be searched in vector.
so here is working solution. you might improve it in details:
struct NameContainer{
char name [32];
};
inline bool operator== (const NameContainer &first,const NameContainer &second){
return (strcmp(first.name,second.name)==0);
}
int main(int argc, char** argv) {
NameContainer* _storedNames = new NameContainer[1];
std::vector<NameContainer> vn(_storedNames, _storedNames + 1);
const char* cc="piotr";
NameContainer nc;
memcpy(nc.name,cc,strlen(cc)+1);
vn.push_back(nc);
NameContainer myObjectPredicate;
memcpy(myObjectPredicate.name,cc,strlen(cc)+1);
int count=std::count(vn.begin(), vn.end(), myObjectPredicate);
std::cout<<count;
return 2400;
}
output:
1
Read the docs on std::count, you'll see that it uses operator== for it's comparisons. Therefore, if you want to use std::count, the thing you want to compare MUST have an operator== defined for it. In your case, you could add one to your NameContainer pretty easily.
Related
I am trying to use std::find on the following vector:
std::vector<LoopDetectorData *> Vec_loopDetectors;
And this is how I am using it:
const LoopDetectorData *searchFor = new LoopDetectorData( (*it).c_str(), "", vehicleName.c_str() );
std::vector<LoopDetectorData *>::iterator counter = std::find(Vec_loopDetectors.begin(), Vec_loopDetectors.end(), searchFor);
This is the definition of LoopDetectorData class with operator == overloading.
class LoopDetectorData
{
public:
char detectorName[20];
char lane[20];
char vehicleName[20];
double entryTime;
double leaveTime;
double entrySpeed;
double leaveSpeed;
LoopDetectorData( const char *str1, const char *str2, const char *str3, double entryT=-1, double leaveT=-1, double entryS=-1, double leaveS=-1 )
{
strcpy(this->detectorName, str1);
strcpy(this->lane, str2);
strcpy(this->vehicleName, str3);
this->entryTime = entryT;
this->leaveTime = leaveT;
this->entrySpeed = entryS;
this->leaveSpeed = leaveS;
}
friend bool operator== (const LoopDetectorData &v1, const LoopDetectorData &v2);
};
It seems that std::find can not find an item even if the item exists in the vector.
std::find() searches by value. So it will compare pointers stored in your vector to the pointer which you just created to serve as search argument. This is dommed to fail: you compare pointers and not the values of the object poitned to.
You shall use std::find_if() instead:
auto counter = std::find_if (Vec_loopDetectors.begin(),
Vec_loopDetectors.end(),
[&searchFor](const LoopDetectorData *f)->bool
{ return *f == *searchFor; }
);
find_if uses a predicate which is here an ad-hoc lambda function that compares the values pointed to by dereferencing the pointers. If you're not comfortable with lambdas, you could use a function poitner instead.
Here a live demo of this alternative, with a comparison to you rinitial attempt.
This question already has answers here:
Comparing arrays for equality in C++
(11 answers)
Closed 9 years ago.
I am trying to do function which compare to arrays and returns true if they are same. Now the arrays are simple, it will be advanced later but I am stuck on the testEqual function.
So here is code
int n = 5;
int array[5] = {5,10,3,4,7};
bubbleSort(pole,n);
int array2[5] = {3,4,5,7,10};
testEqual( array , array2 , "bubbleSort");
And here is testEqual function I need to remake on arrays but I don't know how.
bool testEqual(int i1, int i2, const string testName) {
bool myresult = (i1 == i2);
return myresult;
}
The other functions like bubbleSort are fine I just need to remake testEqual.
Following may help:
template <typename T, std::size_t N>
bool isEqual(const T (&lhs)[N], const T (&rhs)[N])
{
return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
}
If you use std::array, you have that for free. (And the syntax is more friendly).
To compare two arrays you could use standard algorithm std::equal.
For example
bool testEqual( const int *first1, const int *last1, const int *first2, const int *last2 )
{
return std::equal( first1, last1, first2, last2 );
}
It can be called the following way
testEqual( array, array + 5, array2, array2 + 5 );
As for your function then it is invalid.
It simply compares two integers and it is not clear what is the meaning of the third parameter
bool testEqual(int i1, int i2, const string testName) {
bool myresult = (i1 == i2);
return myresult;
}
i see it the same as H2CO3 "what qualifies as equal?"
the approach with std::equal does not match to the arrays you are providing...std::equal will take same elements AND order.
I modified the example from cplusplus.com
int main () {
int myints[] = {20,40,60,80,100};
int myints2[] = {20,100,60,40,100};
std::vector<int>myvector (myints2,myints2+5); // myvector: 20 40 60 80 100
// using default comparison:
if ( std::equal (myvector.begin(), myvector.end(), myints) )
std::cout << "The contents of both sequences are equal.\n";
else
std::cout << "The contents of both sequences differ.\n";
return 0;
}
resulting in
The contents of both sequences differ.
so for using std::equal, you should sort them before
You can also use std::equal. For example :
#include <algorithm>
int *ints;
ints = new int[10];
bool EqualArray(const Object& obj)
{
return std::equal(ints,ints + 10, obj.ints);
}
Of course you can also overload the operator== for other things. Unfortunately you can't overload it for primitive arrays, because overloading operators is only allowed if at least one argument is a class (or struct) type. But you could override it to compare vector with array. Something like:
template<typename T, typename Alloc, size_t S>
bool operator==(std::vector<T, Alloc> v, const T (&a)[S])
{
return v.size() == S && std::equal(v.begin(), v.end(), a);
}
(this takes reference to array not degraded to pointer to check it's declared size first and is therefore safe).
This question already has answers here:
How can I make the map::find operation case insensitive?
(12 answers)
Closed 9 years ago.
I am new to stl's. Here is my below program.
typedef pair<string, int> p;
int main(int argc, char *argv[])
{
map<string,int> st;
st.insert(p("hello",1)); //Inserted "hello" as key to map.
st.insert(p("HELLO",1)); //Inserted "HELLO" as key to map.
cout<<"size="<<st.size()<<endl; //Output is 2 because two records found "hello" and "HELLO"
return 0;
}
I don't want to take account of the repeated case changes(upper case to lower case words or vice-versa). Here "st.insert(p("HELLO",1));" should fail, hence the no. of records should be "1" instead of "2". Is there any flag setup or like so?
I was unable to find the related questions hence posted this question.
Any help is thankful.
Use a custom comparator:
struct comp {
bool operator() (const std::string& lhs, const std::string& rhs) const {
return stricmp(lhs.c_str(), rhs.c_str()) < 0;
}
};
std::map<std::string, int, comp> st;
Edit :
If you're not able to use stricmp or strcasecmp use :
#include<algorithm>
//...
string tolower(string s) {
std::transform(s.begin(), s.end(), s.begin(), ::tolower );
return s;
}
struct comp {
bool operator() (const std::string& lhs, const std::string& rhs) const {
return tolower(lhs) < tolower(rhs);
}
};
std::map<std::string, int, comp> st;
There are two ways to do this
First - change the "comparison" function to ignore case
Second - whenever you use a string to either put or get a value from the map, wrap it with a function that turns it into lowercase.
For the first all you need to do is create a "function class" (a class with operator() ) that receives two strings and returns whether the left is "smaller" than the right:
struct my_comparitor{
bool operator()(const std::string &a, const std::string &b){
// return iwhether a<b
}
};
std::map<std::string,DATA_TYPE,my_comparitor> my_map;
For the second just do this:
std::map<std::string,DATA_TYPE> my_map;
my_map.insert(std::make_pair(TO_LOWERCASE("hello"),1));
iter=my_map.find(TO_LOWERCASE(key));
cout << my_map[TO_LOWERCASE(name)];
// etc.
I'm not sure if a function that transforms to lowercase is already part of stl - but either way it's easy to write.
I am reading a object from a database of type Foo, as defined below. This object is a vector of Foo Members, where a Foo Members consists of a string id and a container object.
typedef std::pair<std::string, Container> FooMember;
typedef std::vector<FooMember> Foo;
I wish to iterate over a Foo object in its sorted form, where sorting is done with respect to the id. To do this I am using the following function to create first a sorted version of the object. As you can see, the object is sorted in a case insensitive manner. Is there a better way for me to iterate over this object compared to how I am currently doing it?
Foo sortedFoo(Foo& value) const {
Foo returnValue;
returnValue.reserve(value.size());
// use a map to sort the items
std::map<std::string, FooMember> sortedMembers;
{
Foo::iterator i = value.begin();
Foo::iterator end = value.end();
for(; i!=end; ++i) {
std::string name = i->first;
boost::algorithm::to_lower(name);
sortedMembers[name] = *i;
}
}
// convert the map to a vector of its values in sorted order
std::map<std::string, FooMember >::iterator i = sortedMembers.begin();
std::map<std::string, FooMember >::iterator end = sortedMembers.end();
for(; i!=end; ++i) {
returnValue.push_back(i->second);
}
return returnValue;
}
Yes: Copy the vector, then use std::sort with a custom comparison predicate:
struct ByIdCaseInsensitive {
bool operator ()(const FooMember& lhs, const FooMember& rhs) const {
return boost::algorithm::to_lower_copy(lhs.first) <
boost::algorithm::to_lower_copy(rhs.first);
}
};
Way more efficient than filling a map, and then copying back to a vector.
The predicate would be even better if it used a proper Unicode collation algorithm, but that isn't available in the standard library or Boost.
You can use std::sort
#include <algorithm>
bool comparator(const FooMember& i, const FooMember& j)
{
std::string str1 = i.first;
boost::algorithm::to_lower(str1);
std::string str2 = j.first;
boost::algorithm::to_lower(str2);
return (str1 < str2);
}
void sortFoo(Foo& value) {
std::sort (value.begin(), value.end(), comparator);
}
Or, you can keep Foo objects in a std::map<std::string, Foo> from the beginning so they remain always sorted.
The best way would be to use std::sort with a custom comparator for FooMembers:
bool cmp(const FooMember& lhs, const FooMember& rhs);
Foo sortedFoo(const Foo& value) const
{
Foo tmp = value;
return std::sort(tmp.begin(), tmp.end(), cmp);
}
where the comparison can be implemented with the help of std::lexicographical_compare and tolower:
#include <cctype> // for std::tolower
bool ci_cmp(char a, char b)
{
return std::tolower(a) < std::tolower(b);
}
#include <algorithm> // for std::sort, std::lexicographical_compare
bool cmp(const FooMember& lhs, const FooMember& rhs)
{
return std::lexicographical_compare(lhs.first.begin(),
lhs.first.end(),
rhs.first.begin(),
rhs.first.end(),
ci_cmp);
}
You can also use std::sort with a lambda expression:
std::sort(value.begin(), value.end(), [](const FooMember &lhs, const FooMember &rhs)
{
std::string str1 = i.first, str2 = j.first;
boost::algorithm::to_lower(str1);
boost::algorithm::to_lower(str2);
return str1 < str2;
});
Or use the version provided by erelender. It's up to you.
Semantically std::vector<std::pair<T,U> > is a std::map<T,U> (but implementations are usually different). If you can re-design Foo, you probably better do it. As side effect, you will get sorting for free.
typedef std::map<std::string, Container> Foo;
I have:
struct MyStruct
{
char* name;
int* somethingElse;
};
And I need to find in a std::vector<MyStruct*> an element (by using std::find_if) whose name is "XYZ" ... but ... the Predicate of std::find_if (if I have managed to understand it correctly) is a plain function, and it takes in a MyStruct pointer and I have no idea where I can specify the extra "XYZ" value to be used in the comparison.
So, how can I use std::find_if or this purpose? (Obviously, looking for a nice solution, not a global variable, or just walk through the list, ....)
Thanks, f
You can use a functor for this (hope I didn't get anything wrong, as I typed it in the browser):
class finder
{
const char* name;
public:
finder(const char* _name): name(_name) {}
bool operator()(MyStruct* elem) {return strcmp(elem->name, name) == 0;}
};
finder f("sample");
std::find_if(myvector.begin(), myvector.end(), f);
If you use C++11 and lambda:
std::vector<MyStruct> mystructus;
std::find_if(mystructus.begin(), mystructus.end(),
[](const MyStruct& ms){ return ms.name == std::string("XYZ"); } );
You have two options, either use functors or lamdas.
Using functors, you create a new class (or structure) whose constructor takes the string you want to search for, then it has an operator() function that is called by std::find_if:
class my_finder
{
std::string search;
public:
my_finder(const std::string& str)
: search(str)
{}
bool operator()(const MyStruct* my_struct) const
{ return search == my_struct->name; }
};
// ...
std::find_if(std::begin(...), std::end(...), my_finder("XYZ"));
The second using lambdas is less code, but requires recent version of the compiler that can handle C++11 lambdas:
std::find_if(std::begin(...), std::end(...), [](const MyStruct* my_struct)
{ return std::string("XYZ") == my_struct->name; });
The last example can even be generalized further:
using namespace std::placeholders; // For `_1` used below in `std::bind`
// Declare a "finder" function, to find your structure
auto finder = [](const MyStruct* my_struct, const std::string& to_find) {
return to_find == my_struct->name;
};
auto xyz = std::find_if(std::begin(...), std::end(...), std::bind(finder, _1, "XYZ"));
auto abc = std::find_if(std::begin(...), std::end(...), std::bind(finder, _1, "ABC"));
This way the lambda can be reused.
Predicate is anything, that can have operator () applied to it (with the expected argument(s) and returns something convertible to bool). A pointer to function is such thing, but so is an object that defines operator().
You need to provide a predicate like this:
struct Comparator
{
Comparator(const char* find) : m_find(find){}
bool operator()(MyStruct* p) const
{
return strcmp(p->name, m_find) == 0;
}
const char* m_find;
};
Then you can std::find_if like this:
vector<MyStruct*>::iterator iter = std::find_if(vec.begin(), vec.end(), Comparator("XYZ"));
if(iter != vec.end())
{
MyStruct* p = *iter;
}
Or if your compiler supports C++11 you can use lambdas and get rid of the predicate functor:
auto it = std::find_if(vec.begin(), vec.end(), [](MyStruct* p) { return strcmp(p->name, "XYZ") == 0;});