Reading in multiple data types to an array of structures, from a .csv file

Hi users of cplusplus,

I hope this question is in the right forum. I figured it'd be a beginner level question because I'm only in my second c++ class.

For our final project we are making a baseball game, and are required to read in the roster from a .csv file. The file contains 18 rows & 9 columns, with the 1st column being the names of the players(strings) and the next 8 columns, being filled in with zeros by default (which will be integers and doubles).
The stats we are keeping track of are:
home runs
strikeouts
singles
doubles
triples
at bats
on base average
batting average
for each individual player.

I've declared the structures, and the array of structures as so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct teamA
{
        string name;
	int homeruns;
	int strikeouts;
	int singles;
	int doubles;
	int triples;
	int atbats;
	double onbaseavg;
	double batavg;
};

teamA rosterA[9];

Just change the 'A' to a 'B' and you have the other structure for the other team.

My instructor provided us this link: http://www.cplusplus.com/forum/general/17771/

to help out with reading in comma delimited files. In all honesty, the link hasn't helped much.
What has confused me most is reading in the different data types. I've got strings and integers, but eventually 2 of those will be doubles because they will be percentages.

This is what I have so far reading in the files:
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
40
//#include <sstream>>
//fstream cfs("roster.csv");
//holder is a string, declared globally, to be a temporary holder for the data being read in

void readIntoStruct()
{
	getline(cfs, holder, ',');
	getline(cfs, holder, ',');
	int i = 0;

	while(!(cfs.eof()))
	{
		getline(cfs, holder, ',');
		getline(cfs, holder, ',');
		rosterA[i].name = holder;  //I assume we can do this because they are both strings
		getline(cfs, holder, ',');
		stringstream(holder)>>rosterA[i].homeruns;    //we have to use stringstream 
		getline(cfs, holder, ',');                    //because holder and .homeruns are 
		stringstream(holder)>>rosterA[i].strikeouts;  //different data types? 
		getline(cfs, holder, ',');                   //(i'm unsure if i interpreted this 
		stringstream(holder)>>rosterA[i].singles;    //correctly)
		getline(cfs, holder, ',');
		stringstream(holder)>>rosterA[i].doubles;
		getline(cfs, holder, ',');
		stringstream(holder)>>rosterA[i].triples;
		getline(cfs, holder, ',');
		stringstream(holder)>>rosterA[i].atbats;
		getline(cfs, holder, ',');
		stringstream(holder)>>rosterA[i].onbaseavg;
		getline(cfs, holder, ',');
		stringstream(holder)>>rosterA[i].batavg;

		i++;
		if(i>=9)
		{
			break;
		}
	}
}
//this is for teamA only, ive replicated this code for teamB as well. 


& this is what I'm using to print out the names (this is just test code to see if I read the file in the right way.)
1
2
3
4
5
6
for(int i=0;i<=9;i++)
{
	cout<<i+1<<" "<<rosterA[i].name<<endl;
	cout<<i+1<<" "<<rosterB[i].name<<endl;

}


except it prints out:
1
1
2
2
3
3...
etc.
...without any names, until 10.

Can anyone help me figure out whats wrong?
Is it the fact I'm storing into multiple data types? or is my syntax wrong? I know I'm missing something...

Thanks in advance,
ReXound
Last edited on
> Just change the 'A' to a 'B' and you have the other structure for the other team.

Why is another (identical) structure required?

Something along these lines, perhaps:

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>

// split a line into delimited values
// assumes that strings are not quoted, and do not contain embedded delimiters
// https://cal-linux.com/tutorials/vectors.html
std::vector<std::string> split_line( const std::string& line, char delimiter = ',' )
{
    std::vector<std::string> result ;

    std::istringstream stm(line) ;
    std::string fld ;
    while( std::getline( stm, fld, delimiter ) ) result.push_back(fld) ;

    return result ;
}

struct team
{
    std::string name;
    int homeruns;
    int strikeouts;
    int singles;
    int doubles;
    int triples;
    int atbats;
    double onbaseavg;
    double batavg;
};

bool to_team( const std::vector<std::string>& values, team& t )
{
    if( values.size() != 9 ) return false ; // expected nine fields

    try
    {
        // http://en.cppreference.com/w/cpp/string/basic_string/stol
        // http://en.cppreference.com/w/cpp/string/basic_string/stof
        t = {
                values[0], // name
                std::stoi( values[1] ), // homeruns
                std::stoi( values[2] ), // strikeouts
                std::stoi( values[3] ), // singles
                std::stoi( values[4] ), // doubles
                std::stoi( values[5] ), // triples
                std::stoi( values[6] ), // atbats
                std::stod( values[7] ), // onbaseavg
                std::stod( values[8] ), // batavg
            };

         return true ;
    }

    catch( const std::exception& ) { return false ; }
}

// read one line containing csv for a team into t
std::istream& get_team( std::istream& stm, team& t )
{
        std::string line ;
        if( std::getline( stm, line) && to_team( split_line(line), t ) ) return stm ;

        t = {} ; // input failed, clear the fields in t
        stm.setstate( stm.rdstate() | std::ios::failbit ) ; // put the stream to a failed state
        return stm ;
}

int main()
{
    std::vector<team> roster_team_a ;
    std::vector<team> roster_team_b ;

    // read team_a roster from file
    {
        std::ifstream file( "team_a_roster.csv" ) ;
        team t ;
        while( get_team( file, t ) ) roster_team_a.push_back(t) ;
    }

    // and like-wise for team b

    // ...
}
Topic archived. No new replies allowed.