Удаление запятой из вывода c ++ - PullRequest
4 голосов
/ 17 апреля 2019

Я написал эту программу, которая сортирует числа по векторам от наибольшего к меньшему, она прекрасно работает, но единственное, что меня беспокоит, - это попытка удалить запятую из последнего числа. Вот мой код

#include <iostream>
#include <vector>
#include <cstdlib>
#include <algorithm>
using namespace std;

int main() {

    vector<int> vi1, vi2, vi3;
    srand(987);

    for (int i = 0; i < 10; ++i) vi1.push_back(rand() % 10);
    sort(vi1.begin(), vi1.end());

    for (int i = 0; i < 10; ++i) vi2.push_back(rand() % 10);
    sort(vi2.begin(), vi2.end())

    while(!vi1.empty() && !vi2.empty()) {
        if(vi1.back()>=vi2.back()) {
            vi3.push_back(vi1.back());
            vi1.pop_back();
        }
        else {
            vi3.push_back(vi2.back());
            vi2.pop_back();
        }
    }

    while(!vi1.empty()) {
        vi3.push_back(vi1.back());
        vi1.pop_back();
    }
    while(!vi2.empty()) {
        vi3.push_back(vi2.back());
        vi2.pop_back();
    }

    for (auto i = vi3.begin(); i != vi3.end(); ++i)
        cout << *i << ", ";
    cout << "\nBye..." << endl;
    return 0;
}

и вот вывод

9, 9, 9, 8, 8, 8, 6, 6, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, 0, 
Bye...

как вы можете видеть после последних 0, есть запятая, которая не имеет смысла грамматически. Как я могу удалить эту запятую?

Ответы [ 2 ]

6 голосов
/ 17 апреля 2019

Вместо удаление самый простой способ - просто напечатать запятые только для значений, отличных от первого:

for (auto i = vi3.begin(); i != vi3.end(); ++i) {
    if(i != vi3.begin()) {
        cout << ", ";
    }
    cout << *i;
}

Я регулярно использую эту идиому для форматирования, например. Списки параметров SQL или аналогичные, где разделитель не нужен после последнего элемента, но для любых других.
Существуют и другие способы обнаружения первого элемента (например, используя переменную bool, инициализированную в true перед началом цикла и установленную в false при первой итерации).
Для вашего примера кажется, что проверка vi3.begin() - самый простой и естественный способ.

Вот общий вариант в псевдокоде:

bool isFirstOutput = true;
for_each(element in list) {
    if(not isFirstOutput) {
        print delimiter;
    }
    print element;
    isFirstOutput = false;
}
0 голосов
/ 03 мая 2019

Если begin, end являются хотя бы двунаправленными итераторами (как у вас), вы можете просто сначала проверить, что begin! = end;если не печатать ничего;если это так, выведите ", " -пунктурованные элементы с приращением begin != std::prev(end) и, наконец, напечатайте *begin().вот так:

main.cpp

#include <utility>

template<typename OStream, typename BiIter, typename Punct>
void punctuated(OStream && out, Punct && punct, BiIter begin, BiIter end)
{
    if (begin != end) {
        for (--end  ;begin != end; ++begin) {
            std::forward<OStream>(out) << *begin << std::forward<Punct>(punct);
        }
        std::forward<OStream>(out) << *begin;
    }
}

#include <iostream>
#include <vector>
#include <list>
#include <set>

int main()
{
    std::vector<int> v0;
    std::vector<int> v1{{1}};
    std::list<int> l{{1,2}};
    std::set<int>s{{3,4,5,6,7}};
    std::cout << "v0 [";
    punctuated(std::cout,",",v0.begin(),v0.end());
    std::cout << "]\n";
    std::cout << "v1 [";
    punctuated(std::cout,",",v1.begin(),v1.end());
    std::cout << "]\n";
    std::cout << "l [";
    punctuated(std::cout,",",l.begin(),l.end());
    std::cout << "]\n";
    std::cout << "s [";
    punctuated(std::cout,"|",s.begin(),s.end());
    std::cout << "]\n";
    return 0;
}

Выход:

g++ -Wall -Wextra main.cpp && ./a.out
v0 []
v1 [1]
l [1,2]
s [3|4|5|6|7]

Live

...