Преобразовать вектор <double> в вектор <string> (элегантный способ)

Я хотел бы знать, есть ли элегантный способ или встроенная функция для преобразования vector<double> в vector<string>. То, что я сделал, просто

#include <iostream>
#include <string>
#include <vector>
#include <sstream>


std::vector<std::string> doubeVecToStr(const std::vector<double>& vec)
{
    std::vector<std::string> tempStr;

    for (unsigned int i(0); i < vec.size(); ++i){
        std::ostringstream doubleStr;
        doubleStr << vec[i];    
        tempStr.push_back(doubleStr.str());
    }

    return tempStr;
}


int main( int argc, char* argv[] )
{
    std::vector<double> doubleVec;
    doubleVec.push_back(1.0);
    doubleVec.push_back(2.1);
    doubleVec.push_back(3.2);

    std::vector<std::string> doubleStr;
    doubleStr = doubeVecToStr(doubleVec);

    for (unsigned int i(0); i < doubleStr.size(); ++i)
        std::cout << doubleStr[i] << "  ";

    std::cout << std::endl;

    return 0;
}

Ответ 1

Существует много способов, но стандартное решение - использовать std::transform с помощью lambda, используя std::to_string для преобразования:

std::transform(std::begin(doubleVec),
               std::end(doubleVec), 
               std::back_inserter(doubleStr),
               [](double d) { return std::to_string(d); } 
              );

И вы можете обернуть это в шаблон функции, чтобы он работал с любым стандартным контейнером:

template<class IteratorIn, class IteratorOut>
void to_string(IteratorIn first, IteratorIn last, IteratorOut out)
{
    std::transform(first, last, out,
                   [](typename std::iterator_traits<IteratorIn>::value_type d) { return std::to_string(d); } );
}

Или в С++ 14, с общей лямбдой:

template<class IteratorIn, class IteratorOut>
void to_string(IteratorIn first, IteratorIn last, IteratorOut out)
{
    std::transform(first, last, out, [](auto d) { return std::to_string(d); } );
}

И вызовите его с любым контейнером (например, он работает с std::list<int>, например):

to_string(std::begin(doubleVec), std::end(doubleVec), std::back_inserter(doubleStr));

Примечания:

  • Если у вас нет компилятора С++ 11, напишите свой собственный шаблон функции to_string:

Пример:

template<class T>
std::string my_to_string(T v)
{
    std::stringstream ss;
    ss << v;
    return ss.str();
}

И используйте его аналогичным образом:

std::transform(doubleVec.begin(),
               doubleVec.end(),
               std::back_inserter(doubleStr), 
               my_to_string<double> );
  • Вы должны reserve() память в выходном векторе, чтобы избежать перераспределения во время std::transform():

например. сделайте следующее:

std::vector<std::string> stringVec;
stringVec.reserve(v.size());   // reserve space for v.size() elements

Живая демонстрация

Ответ 2

Используя copy и ostream_iterator:

#include <vector>
#include <iostream>
#include <sstream>
#include <iterator>

int main()
{
  std::vector<double> numbers{1.0, 2.1, 3.2};
  std::stringstream output;
  std::copy(numbers.begin(), numbers.end(), std::ostream_iterator<double>(output, " "));

  std::cout << output.str() << std::endl;
}

Ответ 3

В общем случае, если у вас есть контейнер T и вы хотите создать контейнер из U из контейнера T, как говорили другие, алгоритм поиска - std::transform.

Если вы не используете С++ 11, здесь std::transform use:

#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <sstream>

std::string Transformer(double d)
{
    std::ostringstream doubleStr;
    doubleStr << d;
    return doubleStr.str();
}

int main()
{
    std::vector<double> doubleVec;
    doubleVec.push_back(1.0);
    doubleVec.push_back(2.1);
    doubleVec.push_back(3.2);

    std::vector<std::string> doubleStr;
    std::transform(doubleVec.begin(), doubleVec.end(), std::back_inserter(doubleStr), Transformer);
    std::copy(doubleStr.begin(), doubleStr.end(), std::ostream_iterator<std::string>(std::cout, "  "));
}

Вывод: 1 2.1 3.2