10

I have a CSV file formatted as below:

1,50,a,46,50,b
2, 20,s,56,30,f
3,35,b,5,67,s
...

How can I turn that to a 2D array so that I could do some calculations?

void Core::parseCSV(){
    std::ifstream  data("test.csv");
    std::string line;
    while(std::getline(data,line))
    {
        std::stringstream lineStream(line);
        std::string cell;
        while(std::getline(lineStream,cell,','))
        {
            //not sure how to create the 2d array here
        }
    }
};
6
  • DId you look at existing answers to similar questions - e.g. here? From those, what did you try, and what trouble did you run into? Commented Dec 11, 2015 at 7:19
  • @TonyD, I have edited the question. Commented Dec 11, 2015 at 7:24
  • What do you expect to have happen with values like a and b? Is there some hard-coded mapping to numeric values you could do calculations with? Or should they be ignored? Do you have to remember them to "solve" some matrix system for their values? If you don't want to deal with those issues initially, you could simply read the values into a std::vector<std::vector<std::string>> values;, which you'd put before the first while loop: inside that loop, push_back an empty vector<std::string> or values.resize(values.size() + 1); if you prefer, then push back cell values inside. Commented Dec 11, 2015 at 7:26
  • Basically, What I want is like I have the id 1,2,3 which goes up to to 2k and have that id associated with all the other values. 1: [50,'a'a,46,50,'b'], 2: [2,20,'s',56,30,'f'].... Commented Dec 11, 2015 at 7:32
  • Why you ask for a 2D array? I see a 1D array of a data structure (made of 6 fields, 4 numbers and 2 strings). Commented Dec 11, 2015 at 7:42

3 Answers 3

9

Try this,

void Core::parseCSV()
{
    std::ifstream  data("test.csv");
    std::string line;
    std::vector<std::vector<std::string> > parsedCsv;
    while(std::getline(data,line))
    {
        std::stringstream lineStream(line);
        std::string cell;
        std::vector<std::string> parsedRow;
        while(std::getline(lineStream,cell,','))
        {
            parsedRow.push_back(cell);
        }

        parsedCsv.push_back(parsedRow);
    }
};

NOTE: this will not work if the content of the columns have ,

Sign up to request clarification or add additional context in comments.

2 Comments

This does not work for csv files where text data is present with comma embedded in it.
@AmoghSarpotdar, you are right this is a well known problem. Have a look at this if it helps: stackoverflow.com/questions/769621/…
3

Following code is working. hope it can help you. It has a CSV file istream_iterator-like class. It is a template so that it can read strings, ints, doubles, etc. Its constructors accept a char delimiter, so that it may be used for more than strictly comma-delimited files. It also has a specialization for strings so that white space characters could be retained.

#include <iostream>
#include <sstream>
#include <fstream>
#include <iterator>

using namespace std;

template <class T>
class csv_istream_iterator: public iterator<input_iterator_tag, T>
{
    istream * _input;
    char _delim;
    string _value;
public:
    csv_istream_iterator( char delim = ',' ): _input( 0 ), _delim( delim ) {}
    csv_istream_iterator( istream & in, char delim = ',' ): _input( &in ), _delim( delim ) { ++*this; }

    const T operator *() const {
        istringstream ss( _value ); 
        T value;
        ss >> value;
        return value;
    }

    istream & operator ++() {
        if( !( getline( *_input, _value, _delim ) ) )
        {
            _input = 0;
        }
        return *_input;
    }

    bool operator !=( const csv_istream_iterator & rhs ) const {
        return _input != rhs._input;
    }
};

    template <>
    const string csv_istream_iterator<string>::operator *() const {
        return _value;
    }

    int main( int argc, char * args[] )
    {
        { // test for integers
            ifstream fin( "data.csv" );
            if( fin )
            {
                copy( csv_istream_iterator<int>( fin ),
                      csv_istream_iterator<int>(),
                      ostream_iterator<int>( cout, " " ) );

                fin.close();
            }
        }

        cout << endl << "----" << endl;

        { // test for strings
            ifstream fin( "data.csv" );
            if( fin )
            {
                copy( csv_istream_iterator<string>( fin ),
                      csv_istream_iterator<string>(),
                      ostream_iterator<string>( cout, "|" ) );

                fin.close();
            }
        }

        return 0;
    }

1 Comment

How do you then access each array? sorry its a noob question
-1

I would go for something like this (untested, incomplete) and eventually refine operator >>, if you have strings instead of chars, or floats instead of ints.

struct data_t
{
  int a ;
  int b ;
  char c ;
  int d ; 
  int e ;
  char f ;
} ;

std::istream &operator>>(std::istream &ist, data_t &data)
{
    char comma ;
    ist >> data.a >> comma 
        >> data.b >> comma
        >> data.c >> comma
        >> data.d >> comma
        >> data.e >> comma
        >> data.f 
    ;
    return ist ;
}
void Core::parseCSV(){
  std::ifstream  data("test.csv");
  std::string line;
  std::vector<data_t> datavect ;
  while(std::getline(data,line))
  {
    data_t data ;
    std::stringstream lineStream(line);
    lineStream >> data ;
    datavect.push_back(data) ;
  }
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.