Counting matches in vector of structs.

2019-07-05 14:35发布

问题:

I have a problem that requires me to count the number of instances within this array that uses either the 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))

回答1:

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);


回答2:

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



回答3:

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.