C++ std::vector 到带有自定义分隔符的字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9277906/
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 12:35:34  来源:igfitidea点击:

std::vector to string with custom delimiter

c++stringvector

提问by nkint

I would like to copy the contents of a vectorto one long stringwith a custom delimiter. So far, I've tried:

我想使用自定义分隔符将 a 的内容复制vector到 long 中string。到目前为止,我已经尝试过:

// .h
string getLabeledPointsString(const string delimiter=",");
// .cpp
string Gesture::getLabeledPointsString(const string delimiter) {
    vector<int> x = getLabeledPoints();
    stringstream  s;
    copy(x.begin(),x.end(), ostream_iterator<int>(s,delimiter));
    return s.str();
}

but I get

但我明白了

no matching function for call to ‘std::ostream_iterator<int, char, std::char_traits<char> >::ostream_iterator(std::stringstream&, const std::string&)'

I've tried with charT*but I get

我试过,charT*但我得到

error iso c++ forbids declaration of charT with no type

Then I tried using charand ostream_iterator<int>(s,&delimiter)but I get strange characters in the string.

然后我尝试使用charandostream_iterator<int>(s,&delimiter)但我在字符串中得到了奇怪的字符。

Can anyone help me make sense of what the compiler is expecting here?

任何人都可以帮助我理解编译器在这里的期望吗?

采纳答案by jpalecek

Use delimiter.c_str()as the delimiter:

使用delimiter.c_str()作为分隔符

copy(x.begin(),x.end(), ostream_iterator<int>(s,delimiter.c_str()));

That way, you get a const char*pointing to the string, which is what ostream_operatorexpects from your std::string.

这样,您就会得到一个const char*指向字符串的指针,这正是ostream_operator您的std::string.

回答by max.kondr

C++11:

C++11:

vector<string> x = {"1", "2", "3"};
string s = std::accumulate(std::begin(x), std::end(x), string(),
                                [](string &ss, string &s)
                                {
                                    return ss.empty() ? s : ss + "," + s;
                                });

回答by Shadow2531

Another way to do it:

另一种方法:

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

template <typename T>
string join(const T& v, const string& delim) {
    ostringstream s;
    for (const auto& i : v) {
        if (&i != &v[0]) {
            s << delim;
        }
        s << i;
    }
    return s.str();
}

int main() {
    cout << join(vector<int>({1, 2, 3, 4, 5}), ",") << endl;
}

(c++11 range-based for loop and 'auto' though)

(c++11 基于范围的 for 循环和“自动”虽然)

回答by Matthieu M.

std::string Gesture::getLabeledPointsString(const std::string delimiter) {
  return boost::join(getLabeledPoints(), delimiter);
}

I am not that convinced about introducting getLabeledPointsStringat this point ;)

getLabeledPointsString在这一点上,我不太相信介绍;)

回答by Matt Balvin

This is an extension to the two answers already provided above as run-time performance seemed to be a theme in the comments. I would have added it as comments, but I do not have that privilege yet.

这是对上面已经提供的两个答案的扩展,因为运行时性能似乎是评论中的主题。我会把它添加为评论,但我还没有那个特权。

I tested 2 implementations for run-time performance using Visual Studio 2015:

我使用 Visual Studio 2015 测试了 2 个实现的运行时性能:

Using stringstream:

使用字符串流:

std::stringstream result;
auto it = vec.begin();
result << (unsigned short)*it++;
for (; it != vec.end(); it++) {
    result << delimiter;
    result << (unsigned short)*it;
}
return result.str();

Using accumulate:

使用累积:

std::string result = std::accumulate(std::next(vec.begin()), vec.end(),
    std::to_string(vec[0]),
    [&delimiter](std::string& a, uint8_t b) {
    return a + delimiter+ std::to_string(b);
});
return result;

Release build run-time performance was close with a couple subtleties.

发布构建运行时性能接近于一些微妙之处。

The accumulate implementation was slightly faster (20-50ms, ~10-30% of the overall run-time (~180ms) on 1000 iterations over a 256 element vector). However, the accumulateimplementation was only faster when the aparameter to the lambda function was passed by reference. Passing the aparameter by value resulted in a similar run-time difference favoring the stringstreamimplementation. The accumulateimplementation also improved some when the result string was returned directly rather than assigned to a local variable that was immediately returned. YMMV with other C++ compilers.

在 256 个元素向量上进行 1000 次迭代时,累加实现稍微快一些(20-50 毫秒,总运行时间的约 10-30%(约 180 毫秒))。但是,accumulate只有a通过引用传递给 lambda 函数的参数时,实现才会更快。a按值传递参数会导致类似的运行时差异有利于stringstream实现。accumulate当直接返回结果字符串而不是分配给立即返回的局部变量时,该实现也改进了一些。YMMV 与其他 C++ 编译器。

The Debug build was 5-10 times slower using accumulateso I think the extra string creation noted in several comments above is resolved by the optimizer.

使用调试版本慢 5-10 倍,accumulate所以我认为优化器解决了上面几条注释中提到的额外字符串创建问题。

I was looking at a specific implementation using a vectorof uint8_tvalues. The full test code follows:

我使用的是寻找一个具体实施vectoruint8_t值。完整的测试代码如下:

#include <vector>
#include <iostream>
#include <sstream>
#include <numeric>
#include <chrono>

using namespace std;
typedef vector<uint8_t> uint8_vec_t;

string concat_stream(const uint8_vec_t& vec, string& delim = string(" "));
string concat_accumulate(const uint8_vec_t& vec, string& delim = string(" "));

string concat_stream(const uint8_vec_t& vec, string& delimiter)
{
    stringstream result;

    auto it = vec.begin();
    result << (unsigned short)*it++;
    for (; it != vec.end(); it++) {
        result << delimiter;
        result << (unsigned short)*it;
    }
    return result.str();
}

string concat_accumulate(const uint8_vec_t& vec, string& delimiter)
{
    return accumulate(next(vec.begin()), vec.end(),
        to_string(vec[0]),
        [&delimiter](string& a, uint8_t b) {
        return a + delimiter + to_string(b);
    });
}

int main()
{
    const int elements(256);
    const int iterations(1000);

    uint8_vec_t test(elements);
    iota(test.begin(), test.end(), 0);

    int i;
    auto stream_start = chrono::steady_clock::now();
    string join_with_stream;
    for (i = 0; i < iterations; ++i) {
        join_with_stream = concat_stream(test);
    }
    auto stream_end = chrono::steady_clock::now();

    auto acc_start = chrono::steady_clock::now();
    string join_with_acc;
    for (i = 0; i < iterations; ++i) {
        join_with_acc = concat_accumulate(test);
    }
    auto acc_end = chrono::steady_clock::now();

    cout << "Stream Results:" << endl;
    cout << "    elements: " << elements << endl;
    cout << "    iterations: " << iterations << endl;
    cout << "    runtime: " << chrono::duration<double, milli>(stream_end - stream_start).count() << " ms" << endl;
    cout << "    result: " << join_with_stream << endl;

    cout << "Accumulate Results:" << endl;
    cout << "    elements: " << elements << endl;
    cout << "    iterations: " << iterations << endl;
    cout << "    runtime: " << chrono::duration<double, milli>(acc_end - acc_start).count() << " ms" << endl;
    cout << "    result:" << join_with_acc << endl;

    return 0;
}

回答by Glen Knowles

string join(const vector<string> & v, const string & delimiter = ",") {
    string out;
    if (auto i = v.begin(), e = v.end(); i != e) {
        out += *i++;
        for (; i != e; ++i) out.append(delimiter).append(*i);
    }
    return out;
}

A few points:

几点:

  • you don't need an extra conditional to avoid an extra trailing delimiter
  • make sure you don't crash when the vector is empty
  • don't make a bunch of temporaries (e.g. don't do this: x = x + d + y)
  • 您不需要额外的条件来避免额外的尾随定界符
  • 确保当向量为空时不会崩溃
  • 不要制作一堆临时文件(例如不要这样做:x = x + d + y)

回答by Awais Rafique

int array[ 6 ] = { 1, 2, 3, 4, 5, 6 };
std::vector< int > a( array, array + 6 );
stringstream dataString; 
ostream_iterator<int> output_iterator(dataString, ";"); // here ";" is delimiter 
std::copy(a.begin(), a.end(), output_iterator);
cout<<dataString.str()<<endl;

output= 1;2;3;4;5;6;

输出= 1;2;3;4;5;6;

回答by max.kondr

faster variant:

更快的变体:

vector<string> x = {"1", "2", "3"};
string res;
res.reserve(16);

std::accumulate(std::begin(x), std::end(x), 0,
                [&res](int &, string &s)
                {
                    if (!res.empty())
                    {
                        res.append(",");
                    }
                    res.append(s);
                    return 0;
               });

it doesn't create interim strings, but just allocate memory once for the whole string result and appends each elem to the end of &res

它不会创建临时字符串,而只是为整个字符串结果分配一次内存并将每个元素附加到 &res 的末尾