Разделить вектор на несколько массивов / вектор C ++ - PullRequest
0 голосов
/ 29 января 2019

У меня проблема с разделением строкового вектора на меньший целочисленный вектор \ массив.Мои входные векторные данные выглядят так:

std::vector<std::string> v(2);
v[0] = "0 14 150";
v[1] = "1 2 220";
//...

Я знаю одно решение: создать три массива и использовать sstream для преобразования данных в целое число.Но я хочу не делать код "спагетти".

Спасибо, Питер.

Ответы [ 3 ]

0 голосов
/ 29 января 2019

Редактировать: Я удалил многословную функцию транспонирования.


Я предполагаю, что вы хотите преобразовать std::vector<std::string> в 2D матрицу std::vector<std::vector<int>>.Например, для вашего примера желаемый результат предполагается равным arr1 = {0,1,...}, arr2 = {14,2,...} и arr3 = {150,220,...}.

Сначала

  • Мы можем использовать std::istream_iterator для извлечения целых чисел из строк.

  • Мы также можем применить конструктор диапазона для создания std::vector<int>, соответствующего каждой строке.

Таким образом, следующая функция будет работать для вас, и она не выглядит как код спагетти по крайней мере для меня.Во-первых, эта функция извлекает два целочисленных массива {0,14,150,...} и {1,2,220,...} как матрицы из переданного строкового вектора v.Поскольку значение по умолчанию, std::istream_iterator, является итератором конца потока, каждый конструктор диапазона считывает каждую строку до тех пор, пока ему не удастся прочитать следующее значение.И, наконец, возвращается транспонированное:

#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;
}

Затем вы можете извлечь целые числа из строкового вектора следующим образом:

DEMO

std::vector<std::string> v(n);
v[0] = "0 14 150";
v[1] = "1 2 220";
...
v[n-1] = "...";

auto matrix = extractNumbers<int>(v);

, где matrix[0] равно arr1, matrix[1] равно arr2 и т. Д. Мы также можем быстро получить их внутренние указатели по auto arr1 = std::move(matrix[0]);.

0 голосов
/ 29 января 2019

Здесь есть некоторые недоразумения.
Вывод моей программы должен иметь три массива / вектора.

Вывод выглядит так:

arr1| arr1| arr3
0   | 14  | 150
1   |  2  | 220
2   |  4  | 130  
0 голосов
/ 29 января 2019

Я нашел функцию разбиения в stackoverflow некоторое время назад.К сожалению, я больше не могу опубликовать ссылку.

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)));
}

Мне понадобится разделитель в ваших строках (кажется, в вашем случае это backspace) и вызову функцию для каждого элемента вашего строкового вектора:

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");
}

Более общее решение может выглядеть следующим образом.Вы можете добавить другие типы к 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");
}
...