views:

50

answers:

2

Hi. I encountered a problem here. I'm using C++ multiset. This is the test file.

Score: 3-1 
Ben
Steven
Score: 1-0 
Ben
Score: 0-0
Score: 1-1 
Cole
Score: 1-2
Ben

I'm using while loop and ifstream (fin1) to read in from the test file above.

multiset<string, less<string> > myset;

while(!fin1.eof())
{

fin1 >> scoreName;

if(scoreName == "Score:")                                               
{
    //calculates number of matches played
}
else
{
    goalCheck = scoreName.substr(1,1);
    if(goalCheck == "-")
    {
        string lGoal, rGoal;
        lGoal = scoreName.substr(0,1);
        rGoal = scoreName.substr(2,1);

        int leftGoal, rightGoal;
        leftGoal = atoi(lGoal.c_str());
        rightGoal = atoi(rGoal.c_str());

        if(leftGoal > rightGoal)   //if team wins
        {
            //some computations
        }
        else if(leftGoal < rightGoal)   //if team loses
        {
            //computations
        }
        else if(leftGoal == rightGoal)   //if team draws
        {
            //computations
        }
        else
        {
            myset.insert(myset.begin(), scoreName);
        }
    }
}

I'm inserting all names into myset (regardless of wins/loses/draws) in my last else statement. But I only require the names of those matches who won/draw.

Those names whose matches lost will not be included in myset. In the test file above, there's only one match that lost (1-2) and I wanted to remove "Ben". How can I do that?

I tried to use myset.erase(), but I'm not sure how to get it point to Ben and remove it from myset.

Any help is much appreciated. Thanks.

A: 

Create a Score class. Add it a non-member operator>>() so you can parse it easily. Then it will be easy for you decide whether to insert a Score object into the set or not:

if( scr.gained - scr.lost >= 0 )
    myset.insert(myset.begin(), scr);
wilhelmtell
But will this insert the names into myset? Or will it just simply insert the "Score: 3-1" into myset instead of the 3 names after it?
Wallace
You can add a list of names into the `Score` object, or you can use a `map` instead of a `set`, to map from names to their scores.
wilhelmtell
A: 

If I understand what you're trying to do, I think it would be easier to remember whether the team had won, drawn or lost when you read the "Score" line and only insert the following lines (ie. "Ben") if the team hasn't lost. Inserting everyone and then erasing ones you didn't want seems overcomplicated to me :)

For reference: If you do need to erase, you would use the find() member to locate an entry matching a given key, and then erase() on the returned iterator to delete it (after checking that find() didn't return an iterator equal to end(), which means the item wasn't found).

Also, you shouldn't pass begin() to insert(). The iterator is a hint as to where the map might insert the item; in practice that's rarely useful. There is an overload of that function which takes only one argument, the item to insert.

Peter
@Peter: Yes, you're right. If the team won or drawn, I will need the names of the players that scored. If the team lost, I will not require the names of the players that scored.Is there a simplier way to do that? I know it's complicated to insert all names and thereafter erasing those names that lost.
Wallace
@Wallace actually that's not complicated at all. It's just that you'll have your set large and then you'll shrink it, so it's a performance penalty. To do that you apply the remove-erase idiom: one line of code.
wilhelmtell
You might maintain a `bool` flag indicating if the team won or drew, and set it to `true` when the team wins or draws, and `false` if they lose. Then only insert if that flag is true. Obviously you need to declare it outside the loop so it isn't reset every time around the loop :)
Peter
@Wilhelm: It's not that much code to erase the name, but he'd be doing the erase immediately after doing the insert, so it seems easier to me to simply not do the insert in the first place than worrying about the semantics of `erase`.
Peter
@Peter no, he'd be doing the erase after inserting all scores into the set. `myset.erase(remove_if(scores.begin(),scores.end(),lost()),myset.end());`
wilhelmtell
@Wilhelm: That doesn't work on his set of strings though, because you can't determine from the strings themselves whether they won or lost. If you could tell from the thing that's getting inserted, why insert it in the first place?
Peter
Yes you can, because `scoreName`, the string the OP inserts, holds everything you need. Just parse it. You need to parse the string anyhow, sure, the question is just when and where you parse it. What I'm suggesting is to break in smaller components the process of parsing the strings and inserting them into the container. One option is "to read `Score` objects", and these objects will parse themselves out of the stream. Another is to insert all the string blobs and them remove what's not necessary. The removal therefore uses an operation which parses the strings — which is elsewhere.
wilhelmtell
@Peter and @William: Thanks for your suggestions. I will try them out.
Wallace