-1

I have a custom class 'team' and one of its attributes is its 'name.' After each 'team' is created, I add it to a vector teamList.

I would like to implement a function that continuously prompts the user for a team name which is not already taken by a team within the teamList. I have the following code:

while (true) {
    string newString;
    bool flag = true;
    getline(cin, newString);
    for (int i = 0; i < teamList.size(); i++) {
        if (teamList[i].name.compare(newString) == 0) flag = false; 
    }
    if (flag == true) {
        return newString;
    } else {
        cout << "name already taken." << endl;
    }
}

However, this code is really ugly; is there a better way to check? Also, a more general question- faced with an issue of ugly code (like this one), what kinds of steps can I take to find a new, cleaner implementation? Thanks.

James Webster
  • 31,873
  • 11
  • 70
  • 114
Michael Hang
  • 199
  • 2
  • 2
  • 15
  • Look into [find](http://www.sgi.com/tech/stl/find.html). – Beta Nov 18 '12 at 03:21
  • the problem with set (and by extension, find) is that it contains all of the general 'structs' that I am using- not a list of the names. therefore, I'd need find a way to compare the user's string to each player.name – Michael Hang Nov 18 '12 at 04:16
  • @MichaelHang that doesn't sound like a problem. Do you care about the ordering of the items inside the container? – juanchopanza Nov 18 '12 at 09:34

2 Answers2

2

I would use std::set, which deals with duplicates for you. As an example, you can see that the class is sorted by the string member, and when three are inserted in main, only two stay because two of the insertions have the same string, so they are treated equal.

#include <iostream>
#include <set>
#include <string>

struct SetThing {
    SetThing(int value, const std::string &value2) : i(value), s(value2){}

    int i;
    std::string s;

    bool operator<(const SetThing &other) const {
        return s < other.s;
    }
};

int main() {
    std::set<SetThing> s;
    s.insert(SetThing(5, "abc"));
    s.insert(SetThing(4, "def"));
    s.insert(SetThing(6, "abc"));
    std::cout << s.size();
}

Now for inserting, you can just reprompt while the second member of the returned pair is false:

do {
    //get input
} while (!teamList.insert(somethingBasedOnInput).second);
chris
  • 60,560
  • 13
  • 143
  • 205
  • If I swapped my vector for a set, how would I ensure that the new string hasn't already been used? I've already considered the .find function of sets, but this would compare the string to the 'team' object, not the team.name fields... – Michael Hang Nov 18 '12 at 04:18
  • @MichaelHang, It compares based on your `operator<`. As you can see in my answer, despite having three different integers, `size()` returns 2 because there are two unique strings and `operator<` only compares the strings. – chris Nov 19 '12 at 18:45
0

define an equality operator in team that can compare a team to a string:

  bool team::operator==(string s) const
  {
    return(s==name);
  }

Then you can use find:

vector<team>::const_iterator itr = find(teamList.begin(), teamList.end(),
                                        newString);

if(itr!=league.end())
  cout << "name already taken" << endl;
Beta
  • 96,650
  • 16
  • 149
  • 150