因为我喜欢一行代码(它们非常有用,可以用于各种奇怪的东西,正如最后您将看到的),这里是使用std :: accumulate和C ++ 11 lambda的解决方案:
std::accumulate(alist.begin(), alist.end(), std::string(),
[](const std::string& a, const std::string& b) -> std::string {
return a + (a.length() > 0 ? "," : "") + b;
} )
使用流操作符时,我发现这种语法很有用,其中我不想让所有种类的奇怪逻辑超出流操作的范围,只是为了进行简单的字符串连接。例如,考虑使用流操作符格式化字符串的方法(使用std:)的返回语句:
return (dynamic_cast<ostringstream&>(ostringstream()
<< "List content: " << endl
<< std::accumulate(alist.begin(), alist.end(), std::string(),
[](const std::string& a, const std::string& b) -> std::string {
return a + (a.length() > 0 ? "," : "") + b;
} ) << endl
<< "Maybe some more stuff" << endl
)).str();
更新:
正如评论中@plexando指出的那样,上面的代码在数组以空字符串开头时会出现错误行为,因为缺少对“第一次运行”的检查,这意味着之前的运行没有产生额外字符,并且 - 在所有运行上运行“是第一次运行”的检查很奇怪(即,代码未经过优化)。
如果我们确切知道列表至少有一个元素,则这两个问题的解决方案都很容易。另一方面,如果我们确切知道列表没有至少一个元素,则可以进一步缩短运行时间。
我认为结果代码并不太好看,所以我将其作为正确的解决方案添加在这里,但我认为上面的讨论仍然有价值:
alist.empty() ? "" :
std::accumulate(
++alist.begin(), alist.end(),
*alist.begin(),
[](auto& a, auto& b) { return a + "," + b; });
注:
- 对于支持直接访问第一个元素的容器,最好使用该元素作为第三个参数,如用
alist[0]
替换向量。
- 根据评论和聊天中的讨论,lambda 仍然会进行一些复制操作。可以通过使用这个(不太美观的) lambda 函数来将其最小化:
[](auto&& a, auto&& b) -> auto& { a += ','; a += b; 返回 a; })
,在 GCC 10 上可以将性能提高超过 x10。感谢 @Deduplicator 的建议。我还在试图弄清楚这里发生了什么。