3

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.

Joe Barnes
  • 45
  • 1
  • 5

1 Answers1

2

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.

dreamlax
  • 93,976
  • 29
  • 161
  • 209
  • Thank you so much! This was really helpful. As a further problem, how could I manipulate the data from different lines in my CSV? For example, let's say I wanted to add the x from line one to the x from line two. And then loop this so I could work out dx = x1 + x2 for every possible combination of two lines. How would I go about this? – Joe Barnes Dec 06 '18 at 02:56
  • @JoeBarnes That's a lot of calculations! You would need to use a loop inside another loop. One loop goes from 0 to `my_records.size() - 2` (e.g. from index 0 to the second-to-last index), call that counter `i`, while the second loop goes `i + 1` to `my_records.size() - 1`, call that counter `j`. Then you can add the two together using `my_records[i].x + my_records[j].x`. – dreamlax Dec 06 '18 at 03:02
  • @JoeBarnes I've updated the code for you so you can have an idea of how this could be done. – dreamlax Dec 06 '18 at 03:09
  • Sorry for the late reply, but the extra code was really helpful! Thank you :) – Joe Barnes Dec 11 '18 at 20:28
  • @JoeBarnes no problem! Don't forget to click on the "tick" next to the answer to mark it as the accepted answer (only if you accept it as the answer of course) – dreamlax Dec 12 '18 at 00:36