Печать списков с запятыми C ++ - PullRequest
46 голосов
/ 17 августа 2010

Я знаю, как это сделать на других языках, кроме C ++, который я вынужден использовать здесь.

У меня есть набор строк, которые я печатаю в списке, и между ними нужна запятая, а не запятая. В java, например, я бы использовал stringbuilder и просто удалял запятую с конца после того, как собрал свою строку. Как мне это сделать в C ++?

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

    out << *iter << ", ";
}
out << endl;

Сначала я попытался вставить этот блок, чтобы сделать это (перемещая печать запятой здесь)

if (iter++ != keywords.end())
    out << ", ";
iter--;

Ненавижу, когда мелочи сбивают меня с толку.

РЕДАКТИРОВАТЬ: Спасибо всем. Вот почему я размещаю подобные вещи здесь. Так много хороших ответов, и решаются по-разному. После семестра Java и ассемблера (разные классы) необходимость выполнения C ++ проекта за 4 дня заставила меня задуматься. Мало того, что я получил свой ответ, я получил возможность подумать о различных способах решения такой проблемы. Потрясающе.

Ответы [ 24 ]

2 голосов
/ 08 мая 2018

Если значения std::string s, вы можете написать это красиво в декларативном стиле с помощью range-v3

#include <range/v3/all.hpp>
#include <vector>
#include <iostream>
#include <string>

int main()
{
    using namespace ranges;
    std::vector<std::string> const vv = { "a","b","c" };

    auto joined = vv | view::join(',');

    std::cout << to_<std::string>(joined) << std::endl;
}

Для других типов, которые должны быть преобразованы в строку, выможно просто добавить преобразование, вызывающее to_string.

#include <range/v3/all.hpp>
#include <vector>
#include <iostream>
#include <string>

int main()
{
    using namespace ranges;
    std::vector<int> const vv = { 1,2,3 };

    auto joined = vv | view::transform([](int x) {return std::to_string(x);})
                     | view::join(',');
    std::cout << to_<std::string>(joined) << std::endl;
}
2 голосов
/ 18 августа 2017

Я предлагаю вам просто переключить первый символ с помощью лямбды.

std::function<std::string()> f = [&]() {f = [](){ return ","; }; return ""; };                  

for (auto &k : keywords)
    std::cout << f() << k;
2 голосов
/ 17 сентября 2015

В питоне мы просто пишем:

print ", ".join(keywords)

так почему бы и нет:

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();
}

, а затем просто используйте его как:

cout << join(", ", keywords) << endl;

В отличие от приведенного выше примера на python, где " " является строкой, а keywords должен быть итерируемым из строк, здесь, в этом примере C ++, разделитель и keywords может быть любым потоком, например

cout << join('\n', keywords) << endl;
2 голосов
/ 23 августа 2016

, чтобы избежать размещения if внутри цикла, я использую это:

vector<int> keywords = {1, 2, 3, 4, 5};

if (!keywords.empty())
{
    copy(keywords.begin(), std::prev(keywords.end()), 
         std::ostream_iterator<int> (std::cout,", "));
    std::cout << keywords.back();
}

Это зависит от типа вектора, int, но вы можете удалить его с помощью некоторого помощника.

1 голос
/ 11 июля 2011

Я использую маленький вспомогательный класс для этого:

class text_separator {
public:
    text_separator(const char* sep) : sep(sep), needsep(false) {}

    // returns an empty string the first time it is called
    // returns the provided separator string every other time
    const char* operator()() {
        if (needsep)
            return sep;
        needsep = true;
        return "";
    }

    void reset() { needsep = false; }

private:
    const char* sep;
    bool needsep;
};

Чтобы использовать это:

text_separator sep(", ");
for (int i = 0; i < 10; ++i)
    cout << sep() << i;
1 голос
/ 29 декабря 2016

Следующие должны сделать: -

 const std::vector<__int64>& a_setRequestId
 std::stringstream strStream;
 std::copy(a_setRequestId.begin(), a_setRequestId.end() -1, std::ostream_iterator<__int64>(strStream, ", "));
 strStream << a_setRequestId.back();
1 голос
/ 17 августа 2010

Может быть так ..

bool bFirst = true;
for (auto curr = keywords.begin();  curr != keywords.end(); ++curr) {
   std::cout << (bFirst ? "" : ", ") << *curr;
   bFirst = false;
}
1 голос
/ 05 июня 2012

Используя boost:

std::string add_str("");
const std::string sep(",");

for_each(v.begin(), v.end(), add_str += boost::lambda::ret<std::string>(boost::lambda::_1 + sep));

, и вы получите строку, содержащую вектор, разделенный запятой.

EDIT: для удаления последней запятой просто введите:

add_str = add_str.substr(0, add_str.size()-1);
1 голос
/ 17 августа 2010

Я думаю, что это должно работать

while (iter != keywords.end( ))
{

    out << *iter;
    iter++ ;
    if (iter != keywords.end( )) out << ", ";
}
0 голосов
/ 25 октября 2016

Можно использовать функторы:

#include <functional>

string getSeparatedValues(function<bool()> condition, function<string()> output, string separator)
{
    string out;
    out += output();
    while (condition())
        out += separator + output();
    return out;
}

Пример:

if (!keywords.empty())
{
    auto iter = keywords.begin();
    cout << getSeparatedValues([&]() { return ++iter != keywords.end(); }, [&]() { return *iter; }, ", ") << endl;
}
...