0

Here I tried to get a specific column from a csv file but I am getting an error on ptr[rowIdx].push_back(value) statement. It gives an error on "value" which is no suitable conversion from string to char.

Here is my code:

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm> 
#include<string.h>
#include<cstdlib>
//std::find
#include<cstring>
using namespace std;
int main(int argc, char** argv)
{
    ifstream fin("filename");
    string line;
    int rowCount = 0;
    int rowIdx = 0; //keep track of inserted rows

    //count the total nb of lines in your file
    while (getline(fin, line)) {
        rowCount++;
    }

    //this will be your table. A row is represented by data[row_number].
    //If you want to access the name of the column #47, you would
    //cout << data[0][46]. 0 being the first row(assuming headers)
    //and 46 is the 47 column.
    //But first you have to input the data. See below.
    string *ptr=new string[rowCount];

    fin.clear(); //remove failbit (ie: continue using fin.)
    fin.seekg(fin.beg); //rewind stream to start

    while (getline(fin, line)) //for every line in input file
    {
        stringstream ss(line);  //copy line to stringstream
       string value;
        while (getline(ss, value, ',')) {       //for every value in that stream (ie: every cell on that row)
            ptr[rowIdx].push_back(value);//add that value at the end of the current row in our table
        }
        rowIdx++;   //increment row number before reading in next line
    }
fin.close();


//Now you can choose to access the data however you like.
//If you want to printout only column 47...

int colNum = 1;  //set this number to the column you want to printout

for (int row = 0; row < rowCount; row++)
{
    cout << ptr[row][colNum] << "\t";  //print every value in column 47 only
}
cout << endl;


return 0;
}

Kindly tell me where is the problem.

  • The `push_back()` member of `std::string` takes a **single character** as its argument. Use the `append` member or just `ptr[rowIdx] += value;`, instead. I'd be surprised if there isn't a duplicate for this, but this one is related: https://stackoverflow.com/q/15082170/10871073 – Adrian Mole Dec 04 '22 at 19:01

1 Answers1

0

You'd be much better off using a matrix of strings to read in the CSV file:

  • No need to parse the file twice.
  • No need to keep count of the lines in the file.
  • You avoid newing memory.

The code below uses a std::istringstream instead of a std::ifstream.

[Demo]

#include <cassert>
#include <iostream>  // cout
#include <sstream>  // istringstream
#include <string>
#include <vector>

int main() {
    std::istringstream file_iss{R"(a,b,c,d,e
1,2,3,4,5
!,@,#,¿,*
)"};

    using row_t = std::vector<std::string>;
    using file_t = std::vector<row_t>;
    file_t file{};

    std::string line{};
    while (getline(file_iss, line)) {
        std::istringstream line_iss{ line };
        std::string value{};
        row_t row{};
        while (getline(line_iss, value, ',')) {
            row.push_back(std::move(value));
        }
        file.push_back(std::move(row));
    }

    size_t col{ 1 };
    assert((not file.empty()) and (col < file[0].size()));
    for (size_t row{ 0 }; row < file.size(); ++row) {
        std::cout << file[row][col] << "\t";
    }
    std::cout << "\n";
}

// Outputs: b   2   @

Notice string* ptr = new string[rowCount]; is not correct for a number of reasons:

  • You are creating an array of strings. That would serve for storing each row. But, if you want to store each column as well, you'd need an array of arrays of strings, something like string** ptr = new string*[rowCount];.
  • Then, once you read a line, you should parse it to know the number of columns, and create an array of strings for that given row: file[rowIdx] = new string[colCount];.
  • Finally, you'd also need a second counter, e.g. colIdx, to access each column's value: file[rowIdx][colIdx] = value;.

The code below hardcodes the number of rows and columns to focus on the handling of the matrix of values.

It doesn't free any memory either, which should be done.

[Demo]

#include <iostream>  // cout
#include <sstream>  // istringstream
#include <string>

int main() {
    std::istringstream file_iss{R"(a,b,c,d,e
1,2,3,4,5
!,@,#,¿,*
)"};

    std::string** file = new std::string*[3];
    std::string line{};
    for (size_t rowIdx{ 0 }; std::getline(file_iss, line); ++rowIdx) {
        file[rowIdx] = new std::string[5];
        std::istringstream line_iss(line);
        std::string value{};
        for (size_t colIdx{ 0 }; std::getline(line_iss, value, ','); ++colIdx) {
            file[rowIdx][colIdx] = value;
        }
    }
    size_t col{ 1 };
    for (size_t row{ 0 }; row < 3; ++row) {
        std::cout << file[row][col] << "\t";
    }
    std::cout << "\n";
}
rturrado
  • 7,699
  • 6
  • 42
  • 62