使用逗号C++打印列表

qua*_*rum 50 c++ pretty-print

我知道如何用其他语言来做这件事,而不是C++,我不得不在这里使用它.

我有一组字符串,我打印到列表中,并且每个字符串之间需要逗号,但不是逗号.例如,在java中,我会使用stringbuilder,并在构建字符串后删除逗号.我如何用C++做到这一点?

auto iter = keywords.begin();
for (iter; iter != keywords.end( ); iter++ )
{

    out << *iter << ", ";
}
out << endl;
Run Code Online (Sandbox Code Playgroud)

我最初尝试插入此块来执行此操作(在此处移动逗号打印)

if (iter++ != keywords.end())
    out << ", ";
iter--;
Run Code Online (Sandbox Code Playgroud)

我讨厌小东西把我绊倒的时候.

编辑:谢谢大家.这就是我在这里发布这样的东西的原因.这么多好的答案,并以不同的方式解决.经过一个学期的Java和汇编(不同的类),不得不在4天内完成一个C++项目,这让我陷入了困境.我不仅得到了答案,还有机会思考解决这类问题的不同方法.真棒.

Jer*_*fin 52

使用infix_iterator:

// infix_iterator.h 
// 
// Lifted from Jerry Coffin's 's prefix_ostream_iterator 
#if !defined(INFIX_ITERATOR_H_) 
#define  INFIX_ITERATOR_H_ 
#include <ostream> 
#include <iterator> 
template <class T, 
          class charT=char, 
          class traits=std::char_traits<charT> > 
class infix_ostream_iterator : 
    public std::iterator<std::output_iterator_tag,void,void,void,void> 
{ 
    std::basic_ostream<charT,traits> *os; 
    charT const* delimiter; 
    bool first_elem; 
public: 
    typedef charT char_type; 
    typedef traits traits_type; 
    typedef std::basic_ostream<charT,traits> ostream_type; 
    infix_ostream_iterator(ostream_type& s) 
        : os(&s),delimiter(0), first_elem(true) 
    {} 
    infix_ostream_iterator(ostream_type& s, charT const *d) 
        : os(&s),delimiter(d), first_elem(true) 
    {} 
    infix_ostream_iterator<T,charT,traits>& operator=(T const &item) 
    { 
        // Here's the only real change from ostream_iterator: 
        // Normally, the '*os << item;' would come before the 'if'. 
        if (!first_elem && delimiter != 0) 
            *os << delimiter; 
        *os << item; 
        first_elem = false; 
        return *this; 
    } 
    infix_ostream_iterator<T,charT,traits> &operator*() { 
        return *this; 
    } 
    infix_ostream_iterator<T,charT,traits> &operator++() { 
        return *this; 
    } 
    infix_ostream_iterator<T,charT,traits> &operator++(int) { 
        return *this; 
    } 
};     
#endif 
Run Code Online (Sandbox Code Playgroud)

用法如下:

#include "infix_iterator.h"

// ...
std::copy(keywords.begin(), keywords.end(), infix_iterator(out, ","));
Run Code Online (Sandbox Code Playgroud)

  • @Martin:因为我从不打扰提交它?我可能应该,想一想...... (4认同)
  • 凉.像那样.为什么在提升中没有这样的东西? (3认同)
  • 这种功能将在C++ 17中与[std :: experimental :: ostream_joiner](http://en.cppreference.com/w/cpp/experimental/ostream_joiner)一起提供,目前适用于GCC 6.0-SVN和Clang 3.9-SVN [在Wandbox上生活](http://melpon.org/wandbox/permlink/04ZzdkPe5QmKc55E).看到我的新答案. (3认同)
  • 提交它.:)您应该发布到邮件列表并询问是否有任何类似的迭代器可能需要. (2认同)
  • @TED:在使用中,它是您发布的代码长度的四分之一,*而且*它的用途也更加广泛​​(例如,如果您想要制表符分隔的输出,那正好是*零*额外工作)。简而言之,额外的长度主要是给出了如何完成工作的一般概念的代码与合理完成并准备使用的代码之间的差异。 (2认同)

Tem*_*Rex 29

在即将推出的实验性C++ 17就绪编译器中,您可以使用std::experimental::ostream_joiner:

#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>

int main()
{
    int i[] = {1, 2, 3, 4, 5};
    std::copy(std::begin(i),
              std::end(i),
              std::experimental::make_ostream_joiner(std::cout, ", "));
}
Run Code Online (Sandbox Code Playgroud)

使用GCC 6.0 SVNClang 3.9 SVN的实例


Jam*_*ong 25

因为每个人都决定用while循环来做这个,所以我将给出一个for循环的例子.

for (iter = keywords.begin(); iter != keywords.end(); iter++) {
  if (iter != keywords.begin()) cout << ", ";
  cout << *iter;
}
Run Code Online (Sandbox Code Playgroud)

  • @TED:什么是"中间测试循环"? (11认同)
  • 或者,如果您_真的_想避免每次都进行比较,您可以执行`auto it = keyword.begin(); if (it != keyword.end()) cout &lt;&lt; it++;` 和 _then_ 以 `cout &lt;&lt; ", " &lt;&lt; it;` 运行循环。不过,就我个人而言,我更喜欢将所有内容都放在一个地方。 (3认同)

Ste*_*sop 18

假设一个模糊的正常输出流,那么写一个空字符串确实无效:

const char *padding = "";
for (auto iter = keywords.begin(); iter != keywords.end(); ++iter) {
    out << padding << *iter;
    padding = ", "
}
Run Code Online (Sandbox Code Playgroud)

  • 两年后有机会再看一遍这个问题,我更喜欢这种方法。聪明的。 (2认同)

Mar*_*k B 16

一种常见的方法是在循环之前打印第一个项目,并仅循环其余项目,在每个剩余项目之前预打印逗号.

或者,您应该能够创建自己的流来维护行的当前状态(在endl之前)并将逗号放在适当的位置.

编辑:您也可以使用TED建议的中间测试循环它将是这样的:

if(!keywords.empty())
{
    auto iter = keywords.begin();
    while(true)
    {
        out << *iter;
        ++iter;
        if(iter == keywords.end())
        {
            break;
        }
        else
        {
            out << ", ";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我首先提到了"在循环之前打印第一项"方法,因为它保持循环体非常简单,但任何方法都可以正常工作.


Kla*_*ark 7

像这样的东西?

while (iter != keywords.end())
{
 out << *iter;
 iter++;
 if (iter != keywords.end()) cout << ", ";
}
Run Code Online (Sandbox Code Playgroud)

  • 没有被贬低,但我对这个解决方案的问题是它每次迭代都会对完全相同的条件进行**两次**检查。 (3认同)

Mat*_* M. 7

有许多聪明的解决方案,并且有太多的解决方案使代码无法超越拯救的希望而不让编译器完成其工作.

明显的解决方案,是特殊情况下的第一次迭代:

bool first = true;
for (auto const& e: sequence) {
   if (first) { first = false; } else { out << ", "; }
   out << e;
}
Run Code Online (Sandbox Code Playgroud)

这是一个死的简单模式:

  1. 不会破坏循环:一目了然,每个元素都会被迭代.
  2. 允许不仅仅是放置一个分隔符,或者实际打印一个列表,因为else块和循环体可以包含任意语句.

它可能不是绝对最有效的代码,但单个预测分支的潜在性能损失很可能被巨大的庞然大物所掩盖std::ostream::operator<<.


T.E*_*.D. 5

我使用分隔符(使用任何语言)的典型方法是使用经过中期测试的循环.C++代码将是:

for (;;) {
   std::cout << *iter;
   if (++iter == keywords.end()) break;
   std::cout << ",";
}
Run Code Online (Sandbox Code Playgroud)

(注意:if如果关键字可能为空,则需要在循环之前进行额外检查)

显示的大多数其他解决方案最终会在每次循环迭代时执行完整的额外测试.你正在做I/O,所以这个时间不是一个大问题,但它会冒犯我的感情.

  • 说到冒犯的敏感性,你在开始时省略了所需的一次性测试,以确保`keywords.size()> 0`或等效.这使您的代码看起来比实际更简单.偷偷摸摸;-) (2认同)

Dar*_*ric 5

在python中我们只写:

print ", ".join(keywords)
Run Code Online (Sandbox Code Playgroud)

那么为什么不:

template<class S, class V>
std::string
join(const S& sep, const V& v)
{
  std::ostringstream oss;
  if (!v.empty()) {
    typename V::const_iterator it = v.begin();
    oss << *it++;
    for (typename V::const_iterator e = v.end(); it != e; ++it)
      oss << sep << *it;
  }
  return oss.str();
}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

cout << join(", ", keywords) << endl;
Run Code Online (Sandbox Code Playgroud)

与上面的python示例不同,the " "is a string and the must keywordsbe an iterable of strings,在这个C++示例中,分隔符keywords可以是任何可流式传输的,例如

cout << join('\n', keywords) << endl;
Run Code Online (Sandbox Code Playgroud)