C++ 将 vector<int> 转换为字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1430757/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:57:05  来源:igfitidea点击:

Convert a vector<int> to a string

c++vectortostring

提问by dzhelil

I have a vector<int>container that has integers (e.g. {1,2,3,4}) and I would like to convert to a string of the form

我有一个vector<int>包含整数的容器(例如 {1,2,3,4}),我想转换为形式的字符串

"1,2,3,4"

What is the cleanest way to do that in C++? In Python this is how I would do it:

在 C++ 中最干净的方法是什么?在 Python 中,我会这样做:

>>> array = [1,2,3,4]
>>> ",".join(map(str,array))
'1,2,3,4'

回答by Brian R. Bondy

Definitely not as elegant as Python, but nothing quite is as elegant as Python in C++.

绝对不如 Python 优雅,但没有什么比 C++ 中的 Python 优雅了。

You could use a stringstream...

你可以用一个stringstream...

#include <sstream>
//...

std::stringstream ss;
for(size_t i = 0; i < v.size(); ++i)
{
  if(i != 0)
    ss << ",";
  ss << v[i];
}
std::string s = ss.str();

You could also make use of std::for_eachinstead.

你也可以使用std::for_each代替。

回答by Martin York

Using std::for_each and lambda you can do something interesting.

使用 std::for_each 和 lambda 可以做一些有趣的事情。

#include <iostream>
#include <sstream>

int main()
{
     int  array[] = {1,2,3,4};
     std::for_each(std::begin(array), std::end(array),
                   [&std::cout, sep=' '](int x) mutable {
                       out << sep << x; sep=',';
                   });
}

See this questionfor a little class I wrote. This will not print the trailing comma. Also if we assume that C++14 will continue to give us range based equivalents of algorithms like this:

请参阅我写的一个小类的这个问题。这不会打印尾随逗号。此外,如果我们假设 C++14 将继续为我们提供基于范围的算法等价物,如下所示:

namespace std {
   // I am assuming something like this in the C++14 standard
   // I have no idea if this is correct but it should be trivial to write if it  does not appear.
   template<typename C, typename I>
   void copy(C const& container, I outputIter) {copy(begin(container), end(container), outputIter);}
}
using POI = PrefexOutputIterator;   
int main()
{
     int  array[] = {1,2,3,4};
     std::copy(array, POI(std::cout, ","));
  // ",".join(map(str,array))               // closer
}

回答by capone

You can use std::accumulate. Consider the following example

您可以使用 std::accumulate。考虑下面的例子

if (v.empty() 
    return std::string();
std::string s = std::accumulate(v.begin()+1, v.end(), std::to_string(v[0]),
                     [](const std::string& a, int b){
                           return a + ',' + std::to_string(b);
                     });

回答by 1800 INFORMATION

Another alternative is the use of std::copyand the ostream_iteratorclass:

另一种选择是使用std::copyostream_iterator类:

#include <iterator>  // ostream_iterator
#include <sstream>   // ostringstream
#include <algorithm> // copy

std::ostringstream stream;
std::copy(array.begin(), array.end(), std::ostream_iterator<>(stream));
std::string s=stream.str();
s.erase(s.length()-1);

Also not as nice as Python. For this purpose, I created a joinfunction:

也不如 Python 好。为此,我创建了一个join函数:

template <class T, class A>
T join(const A &begin, const A &end, const T &t)
{
  T result;
  for (A it=begin;
       it!=end;
       it++)
  {
    if (!result.empty())
      result.append(t);
    result.append(*it);
  }
  return result;
}

Then used it like this:

然后像这样使用它:

std::string s=join(array.begin(), array.end(), std::string(","));

You might ask why I passed in the iterators. Well, actually I wanted to reverse the array, so I used it like this:

你可能会问我为什么传入迭代器。好吧,实际上我想反转数组,所以我这样使用它:

std::string s=join(array.rbegin(), array.rend(), std::string(","));

Ideally, I would like to template out to the point where it can infer the char type, and use string-streams, but I couldn't figure that out yet.

理想情况下,我想模板化到可以推断字符类型的程度,并使用字符串流,但我还想不通。

回答by arekolek

With Boost and C++11 this could be achieved like this:

使用 Boost 和 C++11 可以这样实现:

auto array = {1,2,3,4};
join(array | transformed(tostr), ",");

Well, almost. Here's the full example:

嗯,差不多。这是完整的示例:

#include <array>
#include <iostream>

#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/transformed.hpp>

int main() {
    using boost::algorithm::join;
    using boost::adaptors::transformed;
    auto tostr = static_cast<std::string(*)(int)>(std::to_string);

    auto array = {1,2,3,4};
    std::cout << join(array | transformed(tostr), ",") << std::endl;

    return 0;
}

Credit to Praetorian.

感谢执政官

You can handle any value type like this:

您可以像这样处理任何值类型:

template<class Container>
std::string join(Container const & container, std::string delimiter) {
  using boost::algorithm::join;
  using boost::adaptors::transformed;
  using value_type = typename Container::value_type;

  auto tostr = static_cast<std::string(*)(value_type)>(std::to_string);
  return join(container | transformed(tostr), delimiter);
};

回答by sbi

This is just an attempt to solve the riddle given by 1800 INFORMATION's remarkon his second solution lacking genericity, not an attempt to answer the question:

这只是试图解决1800 INFORMATION关于他的第二个解决方案缺乏通用性的评论所给出的谜语,而不是试图回答这个问题:

template <class Str, class It>
Str join(It begin, const It end, const Str &sep)
{
  typedef typename Str::value_type     char_type;
  typedef typename Str::traits_type    traits_type;
  typedef typename Str::allocator_type allocator_type;
  typedef std::basic_ostringstream<char_type,traits_type,allocator_type>
                                       ostringstream_type;
  ostringstream_type result;

  if(begin!=end)
    result << *begin++;
  while(begin!=end) {
    result << sep;
    result << *begin++;
  }
  return result.str();
}

Works On My Machine(TM).

适用于我的机器 (TM)。

回答by Joe Schneider

Lots of template/ideas. Mine's not as generic or efficient, but I just had the same problem and wanted to throw this into the mix as something short and sweet. It wins on shortest number of lines... :)

很多模板/想法。我的不是通用的或高效的,但我只是遇到了同样的问题,我想把它作为简短而甜蜜的东西加入混合中。它以最短的行数获胜...... :)

std::stringstream joinedValues;
for (auto value: array)
{
    joinedValues << value << ",";
}
//Strip off the trailing comma
std::string result = joinedValues.str().substr(0,joinedValues.str().size()-1);

回答by mheyman

If you want to do std::cout << join(myVector, ",") << std::endl;, you can do something like:

如果你想做std::cout << join(myVector, ",") << std::endl;,你可以做这样的事情:

template <typename C, typename T> class MyJoiner
{
    C &c;
    T &s;
    MyJoiner(C &&container, T&& sep) : c(std::forward<C>(container)), s(std::forward<T>(sep)) {}
public:
    template<typename C, typename T> friend std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj);
    template<typename C, typename T> friend MyJoiner<C, T> join(C &&container, T&& sep);
};

template<typename C, typename T> std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj)
{
    auto i = mj.c.begin();
    if (i != mj.c.end())
    {
        o << *i++;
        while (i != mj.c.end())
        {
            o << mj.s << *i++;
        }
    }

    return o;
}

template<typename C, typename T> MyJoiner<C, T> join(C &&container, T&& sep)
{
    return MyJoiner<C, T>(std::forward<C>(container), std::forward<T>(sep));
}

Note, this solution does the join directly into the output stream rather than creating a secondary buffer and will work with any types that have an operator<< onto an ostream.

请注意,此解决方案直接连接到输出流,而不是创建辅助缓冲区,并且可以与任何在 ostream 上具有 operator<< 的类型一起使用。

This also works where boost::algorithm::join()fails, when you have a vector<char*>instead of a vector<string>.

这也适用于boost::algorithm::join()失败的地方,当你有一个vector<char*>而不是一个vector<string>.

回答by chenfy27

string s;
for (auto i : v)
    s += (s.empty() ? "" : ",") + to_string(i);

回答by iain

I like 1800's answer. However I would move the first iteration out of the loop as as the result of the if statement only changes once after the first iteration

我喜欢1800的答案。但是,我会将第一次迭代移出循环,因为 if 语句的结果仅在第一次迭代后更改一次

template <class T, class A>
T join(const A &begin, const A &end, const T &t)
{
  T result;
  A it = begin;
  if (it != end) 
  {
   result.append(*it);
   ++it;
  }

  for( ;
       it!=end;
       ++it)
  {
    result.append(t);
    result.append(*it);
  }
  return result;
}

This can of course be reduced down to fewer statements if you like:

如果您愿意,这当然可以减少到更少的语句:

template <class T, class A>
T join(const A &begin, const A &end, const T &t)
{
  T result;
  A it = begin;
  if (it != end) 
   result.append(*it++);

  for( ; it!=end; ++it)
   result.append(t).append(*it);
  return result;
}