Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ - Reading .csv file into vectors, whilst skipping first line and specific columns

I'm trying to read in a .csv file that looks like this:

Name,Place,Age,x,y
A,X,1,50,100
B,Y,2,-90,20
C,Z,3,0.4,80
...

Except there are 100 rows of data (plus the header).

I would like to read in the columns Name, Age, x and y and place them in an vector that looks like this:

Name = [Age, x, y]

and do this for all 100 rows (so 100 vectors).

I've tried searching the forum for help but the best help I could get was from c++ Skip first line of csv file , which I modified slightly just to print the Age, x, y.

ifstream data("data.csv");
    if (!data.is_open())
    {
        exit(EXIT_FAILURE);
    }
    string str;
    getline(data, str); // skip the first line
    while (getline(data, str))
    {
        istringstream iss(str);
        string token;
        while (getline(iss, token, ','))
        {
            double Age_x_y = atof(token.c_str());

            if (Age_x_y != 0) {
                cout << Age_x_y << " ";
            }
            cout << endl;
        }
    }

This is nice if it was all I wanted to output, but I believe all the data is just stored as a double. I need the data stored in a vector (or something else like a structure) so that I can manipulate the entries. For example, I would like to work out x+y for each Name.

How can I extract the data in this way?

Any help would be greatly appreciated.

like image 299
Joe Barnes Avatar asked Nov 26 '25 08:11

Joe Barnes


1 Answers

Your parsing of the CSV is good, but be careful that you don't provide any data where the fields have embedded commas. Some CSV formatters allow a field to contain a comma if the field is enclosed in double-quotes for example.

You can create a structure which represents (more or less) a single line in your CSV file.

struct Record
{
    std::string name;
    std::string place;
    int age;
    double x;
    double y;
};

Now, you can parse each line into a Record object (pick an appropriate name for the struct), and then place each Record into a vector. Make sure to include <string> and <vector>.

std::vector<Record> my_records;
while (getline(data, str))
{
    Record record;
    istringstream iss(str);
    string token;

    getline(iss, record.name, ',');
    getline(iss, record.place, ',');

    // use atoi(token.c_str()) if you don't have std::stoi from C++11
    getline(iss, token, ',');
    record.age = std::stoi(token);

    // use atof(token.c_str()) if you don't have std::stod from C++11
    getline(iss, token, ',');
    record.x = std::stod(token);

    getline(iss, token, ',');
    record.y = std::stod(token);

    my_records.push_back(record);
}

// loop through the vector, summing every possible
// combination of x values. The outer loop goes from
// index 0 to the second-to-last index, while the inner
// loop goes from the current outer loop counter to the
// last index.

// Note that this is O(n^2) complexity (even with a
// diminishing inner loop). Increasing the number of
// records can have a very noticeable effect on running
// time.
for (size_t i = 0; i < my_records.size() - 1; i++)
{
    for (size_t j = i + 1; j < m_records.size(); j++)
    {
        std::cout << my_records[i].name << ".x + ";
        std::cout << my_records[j].name << ".x = ";
        std::cout << (my_records[i].x + my_records[j].x) << std::endl;
    }
}

You can also use my_records[i].x + my_records[i].y if you want to output the sum of those values.

like image 64
dreamlax Avatar answered Nov 27 '25 20:11

dreamlax



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!