Search code examples
c++vectorstlostream

Printing a list of integers as comma separated list of numbers with max 10 per line


I have a list of numbers. I would like to print them as comma separated list of numbers, at most 10 numbers per line. The following program snippet puts in the comma separated list of numbers, without using explicit for loop to iterate the vector of integers, may i be able to print 10 numbers at most per line?

  std::vector<int> myvector;
  for (int i=1; i<10; ++i) myvector.push_back(i*10);
  stringstream ss;
  std::copy(myvector.begin(), myvector.end(),
       std::ostream_iterator<int>(ss, ", "));
  cout << "list: " << ss.str() << endl;

The output appears as (with extra comma at the end):

list: 10, 20, 30, 40, 50, 60, 70, 80, 90,

I found a solution to my original problem:

  // print at most 6 per line
  int maxperline = 6;
  std::vector<int>::const_iterator i1,i2,i3;
  stringstream ss;
  ss << "list: ";
  for (i1 = myvector.begin(), i2 = myvector.end(); i1 < i2; i1+=maxperline) {
    i3 = min(i2, i1+maxperline);
    std::copy(i1, i3-1, std::ostream_iterator<int>(ss, ", "));
    ss << *(i3-1) << '\n';
  }
  cout << '\n' << ss.str() << endl;

The output appears as:

list: 10, 20, 30, 40, 50, 60
70, 80, 90

In this approach, we can have flexibility by having maxperline set as value you desire


Solution

  • Have some count of the output item, and use it.

    int count = 0;
    for (int i : myvector) {
      if (count > 0) std::cout << ", ";
      std::cout << i;
      if (count % 10 == 0 && count >0) std::cout << std::endl;
      count++;
    }
    

    If you really want to use <algorithm> you could have an anonymous lambda

    int count;
    std::for_each(myvector.begin(), myvector.end(),
                  [&](int i) {
                       if (count > 0) 
                          std::cout << ", ";
                       std::cout << i;
                       if (count % 10 == 0 && count >0)
                          std::cout << std::endl;
                       count++;
                  });
    

    (we obviously need count and std::cout to be captured and closed by reference in the closure, hence the [&]....)

    but honestly in that particular case it would be pedantic to code using std::for_each like above. Using a plain ranged for loop like my first example is shorter and more appropriate.

    BTW good optimizing compilers (probably including recent GCC invoked as g++ -Wall -O2 -std=c++11) would probably optimize the second solution (using std::for_each) into something equivalent to the first (using for, and without allocating a closure).

    You could even try coding that fragment in purely continuation-passing style (with a different continuation when count==0 and when count%10==0 and otherwise) but that would be sick, unreadable, and compiled less efficiently...