I have problem to split a string vector to smaller integer vector\\array. My input vector data looks like:
std::vector<std::string> v(2);
v[0] = "0 14 150";
v[1] = "1 2 220";
//...
I know one solution, to make three arrays and to use sstream to convert data to integer. But i want to avoid making "spaghetti" code.
Thank you, Peter.
I found a split function at stackoverflow some time ago. Unfortunatly, I cannot post the link anymore.
void split(const std::string & str, std::vector<std::string>& cont, const std::string & delims)
{
std::size_t current, previous = 0;
current = str.find_first_of(delims);
while (current != std::string::npos)
{
cont.push_back(std::move(str.substr(previous, current - previous)));
previous = current + 1;
current = str.find_first_of(delims, previous);
}
cont.push_back(std::move(str.substr(previous, current - previous)));
}
I will need delimiter in your strings (seems to be backspace in your case) and call the function on each element of your string vector:
int main()
{
std::vector<std::string> vec{ "0 14 150","1 2 220" };
std::vector<std::vector<int>> intVec(3,std::vector<int>(vec.size()));
for (int i = 0; i < vec.size(); i++)
{
std::vector<std::string> singleStr;
split(vec[i], singleStr, " ");
for (int j=0; j < singleStr.size();j++)
intVec[j][i] = (std::stoi(singleStr[j]));
}
system("pause");
}
A more generic solution could look like this. You can add further types to BasicVariant
#include <string>
#include <vector>
class BasicVariant
{
private:
std::string str;
public:
BasicVariant(const std::string& _str) :str(_str) {}
BasicVariant(int value) :str(std::to_string(value)) {}
BasicVariant(double value) :str(std::to_string(value)) {}
inline int toInt()const { return *this; }
inline double toDouble()const { return *this; }
inline std::string toString()const { return *this; }
inline bool toBool()const { return toDouble(); }
inline operator int()const { return std::stoi(str); }
inline operator double()const { return std::stof(str); }
inline operator std::string()const { return str; }
inline operator bool()const { return toDouble(); }
};
template<typename T>
void split(const std::string& str, std::vector<T>& sink, const std::string& delims)
{
std::size_t current, previous = 0;
current = str.find_first_of(delims);
while (current != std::string::npos)
{
sink.push_back(std::move(BasicVariant(str.substr(previous, current - previous))));
previous = current + 1;
current = str.find_first_of(delims, previous);
}
sink.push_back(std::move(BasicVariant(str.substr(previous, current - previous))));
}
int main()
{
std::vector<std::string> vec{ "0 14 150","1 2 220" };
std::vector<std::vector<int>> intVec(3, std::vector<int>(vec.size()));
for (int i = 0; i < vec.size(); i++)
{
std::vector<int> row;
split(vec[i], row, " ");
for (int j = 0; j < row.size(); j++)
intVec[j][i] = row[j];
}
system("pause");
}
Edit: I removed a verbose transposing function.
I assume that you want to convert std::vector<std::string>
to a 2D matrix std::vector<std::vector<int>>
. For instance, for your example, the desired result is assumed to be arr1 = {0,1,...}
, arr2 = {14,2,...}
and arr3 = {150,220,...}
.
First,
We can use std::istream_iterator
to extract integers from strings.
We can also apply the range constructor to create a std::vector<int>
corresponding to each string.
So the following function would work for you and it does not seem to be a spaghetti code at least to me. First, this function extract two integer arrays {0,14,150,...}
and {1,2,220,...}
as matrices from a passed string vector v
. Since a default constructed std::istream_iterator
is an end-of-stream iterator, each range constructor reads each string until it fails to read the next value. And finally, transposed one is returned:
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
template <typename T>
auto extractNumbers(const std::vector<std::string>& v)
{
std::vector<std::vector<T>> extracted;
extracted.reserve(v.size());
for(auto& s : v)
{
std::stringstream ss(s);
std::istream_iterator<T> begin(ss), end; //defaulted end-of-stream iterator.
extracted.emplace_back(begin, end);
}
// this also validates following access to extracted[0].
if(extracted.empty()){
return extracted;
}
decltype(extracted) transposed(extracted[0].size());
for(std::size_t i=0; i<transposed.size(); ++i){
for(std::size_t j=0; j<extracted.size(); ++j){
transposed.at(i).push_back(std::move(extracted.at(j).at(i)));
}
}
return transposed;
}
Then you can extract integers from a string vector as follows:
std::vector<std::string> v(n);
v[0] = "0 14 150";
v[1] = "1 2 220";
...
v[n-1] = "...";
auto matrix = extractNumbers<int>(v);
where matrix[0]
is arr1
, matrix[1]
is arr2
, and so on. We can also quickly get internal pointers of them by auto arr1 = std::move(matrix[0]);
.
We have here some misunderstands.
Output of my program should have three arrays/vectors.
The output looks like:
arr1| arr1| arr3
0 | 14 | 150
1 | 2 | 220
2 | 4 | 130
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.