Jump to content
  • Advertisement
Sign in to follow this  
Alessandro

C++: loop iterator after find

This topic is 2502 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'd like to ask how do you get the size of an iterator (i.e. the number of find hits) and how would you actually loop through the results.


std::vector<myObjects::myObjectLib>::iterator findHair;
findHair = std::find_if(myObject.begin(), myObject.end(), HasFaceId(idx));


In this case, findHair is my iterator: I thought I might just use a


int size=findHair.size();


to get its size and then loop the values with findHair.at[0 to size-1] to find the values. But that gives compile errors.
Thanks for any help

Share this post


Link to post
Share on other sites
Advertisement
[font=courier new,courier,monospace]std::find_if[/font] doesn't return a bunch of iterators. It returns the iterator to the *first* element in the range that satisfies the condition. If you want to iterate over all of the elements that meet a condition, you have to keep refinding. i.e.


std::vector<myObjects::myObjectLib>::iterator findHair;
// This is kinda long, but it's actually not complex
for (findHair = std::find_if(myObject.begin(), myObject.end(), HasFaceId(idx)); findHair != myObject.end(); findHair = std::find_if(findHair + 1, myObject.end(), HasFaceId(idx))
{
// now do something with findHar
}


[edit]

Actually, I'll have to double check if [font=courier new,courier,monospace]findHair = std::find_if(findHair + 1, myObject.end(), HasFaceId(idx))[/font] is prone to any errors, since it's possible [font=courier new,courier,monospace]findHair + 1 == myObject.end()[/font], and [font=courier new,courier,monospace]std::find_if [/font]expects the valid range [first, last) to be given. I'm assuming that it checks if [font=courier new,courier,monospace]first == last[/font] before it begins iterating, but I'll have to double check that.

[edit edit]

Node that this code is the same as just doing

std::vector<myObjects::myObjectLib>::iterator findHair;
// This is kinda long, but it's actually not complex
for (findHair = myObject.begin(); findHair != myObject.end(); ++findHair)
{
if (HasFaceId(findHair, idx))
{
// now do something with findHar
}
}

Share this post


Link to post
Share on other sites
Thanks for the example Cornstalk. But how would be possible, for example, to access the set of data returned from a find iterator. I mean, say you want to copy the items returned from the search in a new vector.

Share this post


Link to post
Share on other sites

Thanks for the example Cornstalk. But how would be possible, for example, to access the set of data returned from a find iterator. I mean, say you want to copy the items returned from the search in a new vector.

That part was left out of C++ by accident (no really, it was). You can use something like [font=courier new,courier,monospace]std::remove_copy_if[/font], but you'll have to remember you'll have to invert your logic (that is, you'll be copying the things for which the result is false rather then the ones for which the result is true, so you'll have to design your predicate function accordingly).

Share this post


Link to post
Share on other sites
You can treat the iterator as a pointer; dereference it to get a reference to the object and use the -> operator to access the members of the object.

But if you want to copy it to another list, you can use the pre-defined algorithms in the standard library.
[source]
std::remove_copy_if(myObject.begin(), myObject.end(), std::back_inserter(results), std::not1(HasFaceId(idx)));
[/source]
results is a container (it doesn't have to be a vector, can be pretty much any sequence container) to store the results. I hope it is correct, I have only briefly verified it.

Share this post


Link to post
Share on other sites

Thanks, remove_copy_if works just fine.
Out of curiousity, I suppose there is nothing binary-like to speed it up... rolleyes.gif

I suppose you're hinting at binary search and some algorithm that is better than O(n). You can't do better than O(n) in this case, because you have to check every element to see if it satisfies the condition so you know if that element should be copied or not.

Share this post


Link to post
Share on other sites
I still have troubles using the predicate to test if values match.
In this example I have three point structs that I want to compare with a vector:


Point3D F0,F1,F2;

//check point F0
std::vector<myObjects::myObjectLib>::iterator follicleToHair0;
follicleToHair0 = std::find_if(myObject.begin(), myObject.end(), isMatching(F0));
if (follicleToHair0!=myObject.end())
{
int t=(*follicleToHair0).ID;
QMessageBox::warning( 0, QObject::tr( "Error" ), QObject::tr( QString::number(t) ), QObject::tr( "&OK" ) );
}

//check point F1
std::vector<myObjects::myObjectLib>::iterator follicleToHair1;
follicleToHair1 = std::find_if(myObject.begin(), myObject.end(), isMatching(F1));
if (follicleToHair1!=myObject.end())
{
int t=(*follicleToHair1).ID;
QMessageBox::warning( 0, QObject::tr( "Error" ), QObject::tr( QString::number(t) ), QObject::tr( "&OK" ) );
}

//check point F2
std::vector<myObjects::myObjectLib>::iterator follicleToHair2;
follicleToHair2 = std::find_if(myObject.begin(), myObject.end(), isMatching(F2));
if (follicleToHair2!=myObject.end())
{
int t=(*follicleToHair2).ID;
QMessageBox::warning( 0, QObject::tr( "Error" ), QObject::tr( QString::number(t) ), QObject::tr( "&OK" ) );
}


And here is the predicate:


struct isMatching {
isMatching(Point3D_t myPoint) : id(myPoint) { }
bool operator()(const myObjects::myObjectLib &obj)
{
if (obj.hairControlPoint[0].x < id.x) return true;
if (obj.hairControlPoint[0].x > id.x) return false;
if (obj.hairControlPoint[0].y < id.y) return true;
if (obj.hairControlPoint[0].y > id.y) return false;
return obj.hairControlPoint[0].z < id.z;
}
Point3D id;
};


Since these are float, I was taught in another thread that compare for floats should be done this way.

The problem is that the result returned by the three checks are all the same. There should be something very wrong about what I did here.

Share this post


Link to post
Share on other sites
The predicate for find_if shall return true if you have a match, and false if you don't have a match. That is, you must implement equality. Your predicate looks more like it's implementing a less-than comparison for ordering (for example, as used by std::sort). For example, the predicate for obj=(1, 0, 0) and id=(100, 0, 0) returns true since 1 < 100, and find_if will return that element as a match, but they are not equal.

You want this instead.
[source]
bool operator()(const myObjects::myObjectLib &obj)
{
return obj.hairControlPoint[0].x == id.x && obj.hairControlPoint[0].y == id.y && obj.hairControlPoint[0].z == id.z;
}
[/source]

Since you said they are floatingpoint values, you may want to compare against some limit to determine if they are close rather than identical though. abs(a-b)<eps is a common way to determine if a and b are equal to within eps, so do that test for all three value pairs.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!