我想使用自定义分隔符将vector
的内容复制到一个长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();
}
但我得到
no matching function for call to ‘std::ostream_iterator<int, char, std::char_traits<char> >::ostream_iterator(std::stringstream&, const std::string&)’
我尝试了charT*
,但我得到了
error iso c++ forbids declaration of charT with no type
然后我尝试使用char
和ostream_iterator<int>(s,&delimiter)
但是我在字符串中得到了奇怪的字符。
任何人都可以帮助我理解编译器在这里期待什么吗?
答案 0 :(得分:21)
Use delimiter.c_str()
as the delimiter:
copy(x.begin(),x.end(), ostream_iterator<int>(s,delimiter.c_str()));
这样,您就会得到一个const char*
指向该字符串,这是ostream_operator
期望std::string
所期望的。
答案 1 :(得分: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;
});
答案 2 :(得分:9)
std::string Gesture::getLabeledPointsString(const std::string delimiter) {
return boost::join(getLabeledPoints(), delimiter);
}
我不相信在这一点上引入getLabeledPointsString
;)
答案 3 :(得分:8)
另一种方法:
#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基于范围的循环和'自动'虽然)
答案 4 :(得分:7)
这是上面已经提供的两个答案的扩展,因为运行时性能似乎是评论中的主题。我会把它添加为评论,但我还没有这个特权。
我使用Visual Studio 2015测试了2个运行时性能实现:
使用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();
使用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;
发布构建运行时性能接近于几个细微之处。
累积实现略快(20-50ms,在256个元素向量的1000次迭代中总运行时间的约10-30%(~180ms))。但是,accumulate
实现只有在通过引用传递lambda函数的a
参数时才会更快。按值传递a
参数会导致类似的运行时差异,有利于stringstream
实现。当直接返回结果字符串而不是分配给立即返回的局部变量时,accumulate
实现也改进了一些。 YMMV与其他C ++编译器。
使用accumulate
,Debug构建速度慢了5-10倍,所以我认为上面几条评论中提到的额外字符串创建由优化器解决。
我正在使用vector
uint8_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;
}
答案 5 :(得分:2)
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;
}
几点:
答案 6 :(得分:1)
我知道这是一个古老的问题,但是我有一个类似的问题,以上答案均不能满足我的所有需求,因此我将在此处发布解决方案。
我的要求是:
operator<<()
int8_t
由uint8_t
处理为char
来处理std::stringstream
:也许这是您想要或不想要的东西,所以我希望能够做出选择)char
和std::string
s 这假定为C ++ 11。
我选择使用std::stringstream
,因为它实现了一种标准的但仍可自定义的方式来将某些内容转换为字符串。
任何意见都非常欢迎。
#include <iterator>
#include <sstream>
#include <string>
#include <iostream> // used only in main
#include <vector> // used only in main
template< typename T >
typename std::iterator_traits< T >::value_type
identity(typename std::iterator_traits< T >::value_type v) {
return v;
}
template< typename T > using IdentityType = decltype(identity< T >);
template< class InItr,
typename StrType1 = const char *,
typename StrType2 = const char *,
typename StrType3 = const char *,
typename Transform = IdentityType< InItr > >
std::string join(InItr first,
InItr last,
StrType1 &&sep = ",",
StrType2 &&open = "[",
StrType3 &&close = "]",
Transform tr = identity< InItr >) {
std::stringstream ss;
ss << std::forward< StrType2 >(open);
if (first != last) {
ss << tr(*first);
++first;
}
for (; first != last; ++first)
ss << std::forward< StrType1 >(sep) << tr(*first);
ss << std::forward< StrType3 >(close);
return ss.str();
}
int main(int argc, char** argv) {
const std::vector< int > vec{2, 4, 6, 8, 10};
std::cout << join(vec.begin(), vec.end()) << std::endl;
std::cout << join(vec.begin(), vec.end(), "|", "(", ")",
[](int v){ return v + v; }) << std::endl;
const std::vector< char > vec2{2, 4, 6, 8, 10};
std::cout << join(vec2.begin(), vec2.end()) << std::endl;
std::cout << join(vec2.begin(), vec2.end(), "|", "(", ")",
[](char v){ return static_cast<int>(v); }) << std::endl;
}
输出类似:
[2,4,6,8,10]
(4|8|12|16|20)
[<unprintable-char>,<unprintable-char>,<unprintable-char>,
]
(2|4|6|8|10)
答案 7 :(得分:0)
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;
答案 8 :(得分:-1)
更快的变体:
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;
});
它不会创建临时字符串,但只需为整个字符串结果分配一次内存,并将每个元素附加到&amp; res
的末尾