CodeNoob CodeNoob - 3 months ago 18
C++ Question

How to calculate something in c++?

I am brand new in C++ and data structure. So I am learning and any advice is appreciated. I am trying to extract a csv file which looks like the following in notepad.

Sig1,Sig2,Sig3,Sig4,Sig5,Sig6,Sig7,Sig8
45,200,45,200,45,200,45,200
45,200,45,200,45,200,45,200
45,200,45,200,45,200,45,200
45,200,45,200,45,200,45,200
45,200,45,200,45,200,45,200
45,200,45,200,45,200,45,200
45,200,45,200,45,200,45,200
45,200,45,200,45,200,45,200

I want to calculate the moving average for each column and print out the results for each column. I do know how to read and print the whole csv file by rows and I also know how to calculate the moving average. But I am finding it difficult to put the two things together because I want to calculate the results by "columns" and not rows.I want to use vector(queue(string)) to read the file.

My idea: Suppose I want to read the 1st cell of the row and put it in queue1, the next in queue2 and so on, then I move on to the 2nd row and repeat the process. So the first column would be vector of queue1, then 2nd column would be vector of queue2 and so on. Then I perform moving average for each vector of queue (or column).

Does this sound like a viable idea? Check my code below.
I used the last code of this link to get an idea about how to extract the table from a csv file:
How to read-write into/from text file with comma separated values

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <queue>

using namespace std;

void readCSV(istream &input, std::vector< std::queue<std::string> > &output)
{
//fstream file("c://data//test_data.csv", ios::in);
string csvLine;

// read every line from the stream
while( getline(input, csvLine) )
{
istringstream csvStream(csvLine);
queue<string> csvColumn;
string csvElement;
// read every element from the line that is seperated by commas
// and put it into the vector or strings
while( getline(csvStream, csvElement, ',') )
{
csvColumn.push(csvElement);
}
output.push_back(csvColumn);
}

}

int main()
{
ofstream myfile;
string sig;
fstream file("c://data//test_data.csv", ios::in);
if(!file.is_open())
{
cout << "File not found!\n";
return 1;
}
// typedef to save typing for the following object
typedef queue<string> Q;
typedef vector<Q> csvVector;
csvVector csvData;
const int Number_Size = 8;
int n =8;
double sum1 = 0.0;
double movingAverage = 0.0;

readCSV(file, csvData);
// Read data and perform moving average for each column
for(csvVector::iterator i = csvData.begin(); i != csvData.end(); ++i)
{
for(vector<Q>::iterator j = i ->begin(); j !=i ->end(); ++j)
{
for (int i = 0; i <= (Number_Size - n); i++)
{
sum1 = 0.0;

for( int i=0; int j = i; j < i + n; j++)
{
sum1 += sig[j];
movingAverage = sum1/n;
cout << movingAverage << endl;
}

}
}

}

myfile.close();
system("pause");

}

Answer

The problem with your approach is the way how you parse the csv file and store it. Your code creates a queue holding strings for each row and adds all created queues in a vector. This becomes problematic when you now want to iterate through a column.
Try to create a vector for each element you find in the first row. When processing any other row than the first, access the already existing vectors and add the strings. If you follow this approach, you will end up with vectors holding the content of the columns instead of the rows as it stands now. Here is some sample code:

    void readCSV(istream &input, vector<vector<string>>& vOutput)
    {
        int iRowCnt = 0;    
        string csvLine;

        // read every line from the stream
        while( getline(input, csvLine) )
        {
            int iColCnt = 0;
            istringstream inpStreamLine(csvLine);        
            string strElement;

            // read every element from the line that is separated by commas        
            while( getline(inpStreamLine, strElement, ',') )
            {
                // if first line, create vector for each column
                if (iRowCnt == 0)           
                {
                    vector<string> vColumn;
                    vOutput.push_back(vColumn);
                }
                // access the vector with index iColCnt and add sub string
                vOutput.at(iColCnt).push_back(strElement);
                iColCnt++;
            }        
            iRowCnt++;
        }
    }

    void getNumericValues(vector<vector<string>> &vColumns, vector<vector<int>>& vOutput)
    {   
        // iterate across rows (signals)
        for (vector< vector<string> >::iterator iterCol = vColumns.begin() ; iterCol != vColumns.end() ; ++iterCol) 
        {
            vector<int> vColumn;
            vector<string> *vCol = &(*iterCol);
            // iterate across columns (signal values) while skipping first line 
            // convert strings to integer values and add them to vNumValues 
            for (vector<string>::iterator iterRow = vCol->begin()+1; iterRow < vCol->end(); ++iterRow)
            {
                string strElem = *iterRow;
                string::size_type sz;   
                vColumn.push_back(stoi(strElem, &sz));
            }
            vOutput.push_back(vColumn);
        }
    }

    void getMovingAveragesColumn(vector<int> &vNumValues, int iWndSize, vector<int>& vOutput)
    {   
        if (vNumValues.size()<iWndSize)        // check if we have enough values 
            return;                 

        for (vector<int>::iterator iter = vNumValues.begin() ; iter < vNumValues.end()-iWndSize ; ++iter) 
        {
            int iMovAvg = 0;
            for (int ii=0; ii<iWndSize; ii++)
            {
                iMovAvg+= *(iter+ii);
            }
            iMovAvg /= iWndSize;
            vOutput.push_back(iMovAvg);
        }   
    }

    void getMovingAveragesMatrix(vector<vector<int>> &vNumValues, int iWndSize, vector<vector<int>>& vOutput)
    {   
        for (vector<vector<int>>::iterator iterCol = vNumValues.begin() ; iterCol < vNumValues.end() ; ++iterCol) 
        {
            vector<int> *vCol = &(*iterCol);
            vector<int> vMovAvg;
            getMovingAveragesColumn(*vCol, iWndSize, vMovAvg);
            vOutput.push_back(vMovAvg);
        }
    }


    int _tmain(int argc, _TCHAR* argv[])
    {
        ofstream myfile;
        fstream file("c://tmp//test_data.csv", ios::in);
        if(!file.is_open())
        {
            cout << "File not found!\n";
            return 1;
        }
        // vector of vectors for storing strings in matrix form 
        vector<vector<string>> vData;
        readCSV(file, vData);

        // convert to integers 
        vector<vector<int>> vNumValues;
        getNumericValues(vData, vNumValues);    

        // get moving average values
        vector<vector<int>> vMovAverages;
        getMovingAveragesMatrix(vNumValues, 3, vMovAverages);

            // print the moving average values     
        for (vector<vector<int>>::iterator iterCol = vMovAverages.begin() ; iterCol < vMovAverages.end() ; ++iterCol) 
        {
            vector<int> *vCol = &(*iterCol);
            for (vector<int>::iterator iterRow= vCol->begin() ; iterRow < vCol->end() ; ++iterRow) 
            {
                cout<< *iterRow << " ";
            }
            cout<<"\n";
        }

        myfile.close();
        system("pause");
    }
Comments