For your example:
123, A, 4
432, B, 2
321, C, 5
|
(Terminating commas removed)
It seems likely that you want to have a special class to handle each
record (or line) of data. For example (assuming your data represents a role-playing type character):
1 2 3 4 5 6
|
struct player_t
{
unsigned hit_points;
char character_class;
int spells_learned;
};
|
Next you need an overloaded input operator to read a single record, or, for these examples, a "player_t":
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
std::istream& operator >> ( std::istream& ins, player_t& player )
{
// First, get the entire line from the input stream.
std::string raw_csv_data;
std::getline( ins, raw_csv_data );
// Now we'll separate out the pieces of the line
// For each item, we'll read the proper datum,
// then skip over the comma separating it from the next.
std::istringstream iss( raw_csv_data );
try
{
iss >> player.hit_points;
iss >> std::ws;
if (iss.get() != ',') throw 0;
iss >> player.character_class;
iss >> std::ws;
if (iss.get() != ',') throw 0;
iss >> player.spells_learned;
// At this point, the input line should be exhausted. If the
// line is in any other state, that's an error we need to perpetuate
// back to the caller.
if (!iss.eof())
{
ins.setstate( iss.getstate() );
}
}
catch (int)
{
// If we get here, something went wrong trying to skip commas...
ins.setstate( std::ios::failbit );
}
// That's it for this record. As always, return the caller's input stream.
return ins;
}
|
That was, fortunately, the most difficult part. Next it is easy. To read an entire file of records, simply make yourself a type and an overloaded operator to do it:
1 2 3
|
typedef std::vector <player_t> player_list_t;
// That's a list of players, of course.
|
1 2 3 4 5 6 7 8 9 10 11
|
std::istream& operator >> ( std::istream& ins, player_list_t& player_list )
{
player_t player;
while (ins >> player)
{
player_list.push_back( player );
}
return ins;
}
|
Load your file normally:
1 2 3 4 5 6 7 8
|
player_list_t all_players;
std::ifstream f( input_file_name.c_str() );
f >> all_players;
if (!f) fooey(); // (always check to make sure nothing went wrong)
f.close();
std::cout << "There are " << all_players.size() << " player characters in the file.\n";
|
The final part of your question, finding the maximum value, is a little involved, but straightforward. You need
predicate functions -- those that return true or false given arguments -- that compares two records ("player_t"s, or whatever you've got) for the specific column.
For example, a predicate that can sort the second column (the player's character class) is simple enough. The predicate should be the same as the
<
comparison operator.
1 2 3 4
|
bool player_character_class_less_than( const player_t& lhs, const player_t& rhs )
{
return lhs.character_class < rhs.character_class;
}
|
With this predicate, you can use an <algorithm> to either sort all the players by their character class or find the lowest or largest character class:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
unsigned index = std::distance(
std::max_element(
all_players.begin(),
all_players.end(),
player_character_class_less_than
),
all_players.begin()
);
std::cout
<< "The player with the highest character class is number "
<< (index + 1) // Computers start counting at zero, but humans start at one.
<< ".\n";
|
What that did is essentially find the character with 'C' (given the example data), convert it (via the
distance() algorithm, found by #including <iterator>) to an index into the player list, and display it to the user in a human-friendly way.
Hope this helps. Remember, I just typed all this in (I have not compiled it to test against stupid errors). I may have mis-typed something. Good luck!