I have a function to calculate moving average:
void MovingAverage(double inputSeries[]
, size_t inputSize, size_t window, float* output )
My train of thought to do my calculation:
- construct a loop and extract one row of
vec2D
each time - use the
MovingAverage
function to get output
For the first step, the 2d-vector is parsed from a csv file:
std::vector<std::vector<std::string>> vec2D{
{"S0001","01","02","03"}, {"S0002","11","12","13"}, {"S0003","21","22","23"}
};
I want to extract one row of this 2D vector (say the 2nd) and store the row as a 1d vector std::vector<double> copyRow
then calculate the moving average for each row.
copyRow = {11,12,13}
I tried vector<double> copyRow(vec2D[0].begin(), vec2D[0].end());
but it doesn't work because the 2D vector is std::string
type.
I also tried for loops:
int rowN = vec2D.size();
int colN = vec2D[0].size();
double num;
for (int i = 0; i < rowN; i )
{
for (int j = 0; j < colN; j )
{
num = stod(vec2D[i][j]);
copyRow[i][j].push_back(num);
}
}
But it appends all values from all rows into the vector. What would be the best way to do this?
CodePudding user response:
I tried
vector<double> copyRow(vec2D[0].begin(), vec2D[0].end());
but it doesn't work because the 2D vector is string type.
You can make use of the algorithm function std::transform
from <algorithm>
to do this.
Since the first element of each row cannot be transformed to a double
, you can skip it by starting from one element after begin iterator:
#include <algorithm> // std::transform
std::vector<double> copyRow;
// reserve memory for unwanted real locations
copyRow.reserve(vec2D[1].size() - 1u);
std::transform(std::cbegin(vec2D[1]) 1, std::cend(vec2D[1])
, std::back_inserter(copyRow), [](const auto& ele) {
return std::stod(ele);
});
CodePudding user response:
After the comments in the main thread, it seems that the initial data structure (a 2D vector of strings), doesn't seem to be the best choice.
Instead, an associative container, such as a std::map
or std::unordered_map
would seem to be more suited for the task you're trying to accomplish. Basically, the key to the map is the non-numeric field, and the data would be the vector<double>
associated with the key.
Then it just becomes a matter of getting a reference to the row of doubles, given the key value.
Here is an example of code that illustrates this:
#include <map>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
std::string test = "S0001,01,02,03,S0002,11,12,13,S0003,21,22,23";
int main()
{
std::map<std::string, std::vector<double>> mymap;
int numCols = 4;
int count = 0;
std::istringstream strm(test);
std::string data;
std::string id;
while(std::getline(strm, data, ','))
{
if ( count % numCols == 0)
id = data;
else
mymap[id].push_back(stod(data));
count;
}
for (auto& m : mymap)
{
std::cout << "\n" << m.first << "\n";
for (auto& v : m.second)
std::cout << " " << v << "\n";
}
// Get the vector associated with S0002
std::cout << "\nHere is the data for S0002:" << "\n";
std::vector<double>& vDouble = mymap["S0002"];
for (auto& d : vDouble)
std::cout << d << " ";
}
Output:
S0001
1
2
3
S0002
11
12
13
S0003
21
22
23
Here is the data for S0002:
11 12 13
There are two main points:
The vector of strings no longer becomes an issue, since on the population of the
std::vector<double>
elements, thestd::stod
is called on the string to convert the string to a double.Accessing the
std::vector<double>
becomes trivial -- all you need to do is get the key (the string data) and access (by reference in this example), the vector associated with the key. No copying, nostd::transform
calls, or anything like that.