0

I am reading a CSV file and storing it in vector vector string. I want to print the data and for that I am using two for loops one iterating over vector of vector and other iterating over the vector string.

a1,b1,c1,d1
a1,b1,c4,d3
a1,b2,c2,d2
a2,b3,c3,d4
a2,b4,c3,d4

this is the CSV data I am reading. Below code I am using to print it to screen

void ReadCSV::printdata(vector<vector<string>> ipd){
    for(auto it1 = ipd.begin();it1 != ipd.end();++it1){
        vector<string> test = *it1;
        for(auto it2 = test.begin();it2 != test.end();++it2){
            string r = "";
            r= *it2;
            cout<<r<<" ";
        }
        cout<<endl;
    }
}

But the output I am getting seems is not iterating properly:

a1 b1 c1 d1 
a1 b1 c1 d1 a1 b1 c4 d3 
a1 b1 c1 d1 a1 b1 c4 d3 a1 b2 c2 d2 
a1 b1 c1 d1 a1 b1 c4 d3 a1 b2 c2 d2 a2 b3 c3 d4 
a1 b1 c1 d1 a1 b1 c4 d3 a1 b2 c2 d2 a2 b3 c3 d4 a2 b4 c3 d4

I used below code to read data:

vector<vector<string>> ReadCSV:: ReadData(){
    fstream fin(filename);
    vector<string> temp;
    string val1, val2, val3 ,val4;
    if(!fin.is_open()){
        cout<<"ERROR: file open";
    }
    cout<<"FIRST OUTPUT: "<<endl;
    while(fin.good()){
        getline(fin, val1,',');
        //store
        temp.push_back(val1);
        cout<<val1<<" ";
        getline(fin, val2,',');
        temp.push_back(val2);
        cout<<val2<<" ";
        getline(fin, val3,',');
        temp.push_back(val3);
        cout<<val3<<" ";
        getline(fin, val4,'\n');
        temp.push_back(val4);
        cout<<val4<<" ";
        csvdata.push_back(temp);
    }
    cout<<endl;
    return csvdata;
}

Can anyone tell where I am going wrong, other issue I face is when I run debugger (ECLIPSE IDE) and hover over a variable it opens up some popup but doesn't displays the value of the variable, such as "string r" in this case. thanks

howlger
  • 31,050
  • 11
  • 59
  • 99
adi_226
  • 41
  • 1
  • 7
  • 2
    Are you sure that the error is in the `printdata` function, and not with how you read (or otherwise process) the data? Have you tried to step through the code statement by statement in a debugger while monitoring variables and their values and contents? – Some programmer dude Oct 19 '19 at 02:01
  • Agree with @Someprogrammerdude It looks like the error is most likely in the reading that populates `vector>` – doug Oct 19 '19 at 02:04
  • Yes I did debugging on reading part, i have updated the reading code in the description – adi_226 Oct 19 '19 at 02:04
  • 3
    Time to do some [rubber duck debugging](https://en.wikipedia.org/wiki/Rubber_duck_debugging) of that reading code. What happens with `temp` when you read the contents of the file? Will `temp` ever be "reset" or cleared? – Some programmer dude Oct 19 '19 at 02:06
  • 1
    You are simply appending data to temp each time. You need to clear it after each line. – doug Oct 19 '19 at 02:07
  • Also please read [Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons) Doing `while (fin.good())` is just the same. – Some programmer dude Oct 19 '19 at 02:07
  • Unrelated: `void ReadCSV::printdata(vector> ipd)` should be a oneliner. ... if "`ReadCSV::printdata`" doesn't raise concerns. – Ted Lyngmo Oct 19 '19 at 02:07
  • As for how to solve your problem, try to define variables in the closest scope where they are needed. In your case, `temp` and `val1` through `val4` could all be defined inside the loop. – Some programmer dude Oct 19 '19 at 02:09
  • @Someprogrammerdude I like your rubber duck debugging suggestion best but I commented before I saw your comment. – doug Oct 19 '19 at 02:11
  • @TedLyngmo how can i write this as a one-liner? – adi_226 Oct 19 '19 at 17:31
  • @adi_226 Before I answer that - Doesn't the combination `ReadCSV::printdata` look a little bit suspicious? – Ted Lyngmo Oct 20 '19 at 00:53
  • @TedLyngmo sorry but I don't understand what you are pointing to. – adi_226 Oct 20 '19 at 00:58
  • A class named `Read...` and a method named `print...` does look a bit conflicting. – Ted Lyngmo Oct 20 '19 at 01:06
  • @TedLyngmo okay, i can change the class name to CsvReader. – adi_226 Oct 20 '19 at 01:11
  • @adi_226 Something like `void ReadCSV::printdata(const std::vector>& ipd) { std::for_each(ipd.begin(), ipd.end(), [](const auto& v) { std::copy(v.begin(), v.end(), std::ostream_iterator(std::cout, " ")); }); }` should work. – Ted Lyngmo Oct 20 '19 at 12:38

1 Answers1

0

Your CSV reader besides having some minor issues is hard-coded to read exactly 4 comma separated values. Here is a more general code which can read as many lines and with each line having variable number of comma separated values.

#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>
#include <algorithm>

template<typename In, typename Out>
void csv2vec(In first, In last, Out& result) {
    std::string temp;
    unsigned i{0};
    while(1) {
        do{
            if(*first == '\n') break;
            temp.push_back(*first);
            ++first;
        }while(*first != ',' && first != last);
        result[i].push_back(temp);
        if(*first == '\n') {
            ++i;
            result.resize(i+1);
        }
        temp.clear();
        if(first == last) break;
        ++first;
    }
}

int main(void) {
    std::vector<std::vector<std::string>> vec(1);
    std::ifstream in("data.txt");
    std::istreambuf_iterator<char> begin(in);
    std::istreambuf_iterator<char> end;
    csv2vec(begin,end,vec);

    for(const auto& vecouter : vec) {
        for(const auto& elem : vecouter){
            std::cout<<elem<<" ";
        }
        std::cout<<"\n";
    }
   return 0;
}

Note: I have used istreambuf_iterator which never skips any characters (including whitespaces such as '\n'). It grabs whatever's next in the stream buffer unlike istream_iterator which skips whitespaces. Also istream_iterator is useful when performing formatted input and is slower than the istreambuf_iterator. Reference: Item 29, Effective STL, Scott Meyers.

nae9on
  • 249
  • 3
  • 9