Использование getline () в массиве - PullRequest
0 голосов
/ 19 января 2020

Сегодня я составлял одну программу, в основном она использует маршруты городов, которые вы посетили в прошлом, и в конце она должна возвращать весь маршрут вашей поездки, маршруты.

На первой строке вы ' введите число городов, которые вы посетили в прошлом (включая ваш родной город), * ​​1003 *.

Предположим, что наш родной город - Париж. Во второй строке вы вводите свой родной город (Paris в нашем случае).

В следующих N строках вы вводите маршруты своих поездок, они не должны быть в порядке, как вы их сделали, поэтому они могут быть в любом порядке:

Ввод:

4  
Paris  
Berlin-Paris  
Paris-Zagreb  
Ljubljana-Berlin   
Zagreb-Ljubljana  

Вывод:

Paris-Zagreb-Ljubljana-Berlin-Paris

Это мой код, написанный на c ++:

#include <iostream>
#include <string>
using namespace std;
string s[1000],city;
int n;  

int main(){
    cin>>n;
    cin>>city;
    for(int i=0;i<n;i++){
        cin>>s[i];
    }
    cout<<city;
    for(int j=0;j<n;j++){
        for(int i=0;i<n;i++){
            if(s[i].substr(0,city.length())==city){
                city=s[i].substr(city.length()+1);
            cout<<"-"<<city;
            s[i]='\0';
            }   
        }   
    }


}

Это не самый эффективный способ сделать это, я знаю ... И он работает только с городами, состоящими из одного слова (не работает для Нью-Йорка и других городов с 2+ адресами)

Теперь мой вопрос: есть ли простой способ сделать это с 2+ адресными городами? как Нью-Йорк?
Я пытался использовать getline (cin, city) и getline (cin, s [i]), но по какой-то причине это не работает, может быть, я сделал это неправильно.

При попытке с getline() я заметил, что когда я пытался ввести строку s [i] с помощью getline(), мой l oop for(int i=0;i<n;i++) только пошел к n-1, я имею в виду, что я не мог ввести n строки в этом массиве. Например, если бы я использовал N = 5, я мог бы ввести только 4 строки

for(int i=0;i<5;i++){
    getline(cin,s[i]);
}

Давайте введем 4 строки, а

for(int i=0;i<5;i++){
    cin>>s[i];
}

Давайте введем 5 строк


Тоже нет заметил, что если у меня есть какой-нибудь простой код:

#include <iostream>
#include <string>
using namespace std;
string city;
int n;  

int main(){
    cin>>n;
    getline(cin,city);
    cout<<city;
}

Я думал, что он должен вывести название города, но это не так, может кто-нибудь объяснить, почему?

Может быть, я что-то упустил, вот и все ...
Спасибо за чтение, если вы знаете ответ, пожалуйста, помогите мне:)

Ответы [ 2 ]

0 голосов
/ 19 января 2020

существует ли простой способ сделать это с 2+ словами, такими как Нью-Йорк?

Ответ: Да.

Как отмеченный в ответе @ jackw11111 , ваша проблема с чтением имен, содержащих пробел , была вызвана std::cin, который читает только с начала строки до первого пробела . Так, например, попытка чтения "New York" с помощью std::cin >> city; приведет к city, содержащему "New", тогда как "York" останется в stdin непрочитанным.

Решение состоит в том, чтобы использовать getline, что будет читать до тех пор, пока не будет указан символ-разделитель (по умолчанию: '\n').

Теперь, для остальной части вашей проблемы, читая этапы поездки с двумя (или более) городами, разделенными '-', есть количество способов, которыми вы можете подойти к проблеме. Поскольку каждый этап поездки будет включать от и до города, использование std :: pair , предоставленного как часть заголовка STL utility, обеспечит удобный способ хранения связанных из и до городов. Затем вы можете использовать std::vector<std::pair<..,..>>, чтобы создать вектор пар .

Если вам абсолютно не нужно читать первое целое значение для числа предпринятые поездки - вы можете покончить с этим, так как он действительно не нужен для обработки ввода. На самом деле все, что вам нужно, это ваш home город, а затем вы можете прочитать столько строк ввода, сколько захотите, и сохранить столько поездок от и до пар города до EOF при чтении из файла или вводится пустая строка для указания конца ввода.

Для разделения строк читайте с getline, используя std :: stringstream . Для чтения из std::stringstream вы можете использовать getline еще раз (с разделителем '-'), чтобы отделить города от-до в строке. Помещение строки в поток строк и последующее чтение из потока строк не позволяет getline пропустить '\n', когда разделитель был заменен на что-то другое.

Так что в вашем случае вы можете объявить вектор пар строк, а также несколько дополнительных строк для хранения home и помощи в разборе, и вы можете просто прочитать сначала город home, например,

#include <iostream>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

int main (void) {

    std::string home, last, trip, total;    /* strings */
    std::vector<std::pair<std::string, std::string>> vp {}; /* vector of pairs */

    std::cout << "enter home city: ";       /* prompt for home city */
    if (!getline (std::cin, home)) {        /* read/validate home city */
        std::cerr << "error: failed to read home-city.\n";
        return 1;
    }

Теперь просто l oop, читая строки ввода и проверка, является ли строка пустой, чтобы указать конец ввода. Создайте поток строк из каждой строки, а затем прочитайте поток строк с помощью getline (это устраняет необходимость использования substr для анализа городов из строки). Добавьте каждую пару городов от-до к вашему вектору, используя std :: make_pair :

    /* prompt for trips (any number of legs per-line), ENTER alone when done */
    std::cout << "\nenter trips (format city1-city2[-cityN]) "
                    "[Enter] alone when done\n\ntrip: ";
    while (getline (std::cin, trip)) {      /* while trip entered */
        if (!trip.length())                 /* if empty (zero length) break */
            break;
        std::stringstream ss (trip);        /* create stringsteam from line */
        std::string from, to;               /* strings for from and to cities */
        if (getline (ss, from, '-')) {      /* get from city from stringstrem */
            while (getline (ss, to, '-')) { /* get to city from stringstream */
                vp.push_back(std::make_pair (from, to));  /* add pair to vector */
                from = to;                  /* update from = to */
            }
        }
        std::cout << "trip: ";              /* prompt for next trip */
    }

Наконец, просто l oop над сохраненными парами ( с вложенными циклами), чтобы выбрать все этапы отключения на основе от-до , а затем найти следующее, установив from = to; и найдя следующее совпадение. (вы также можете добавить дополнительные проверки, чтобы убедиться, что на каждой итерации найдены правильные значения от-до - что вам остается - что-то простое, как bool found; сделает)

    total = home;                           /* initialize total & last to home */
    last = home;
    for (auto t1 : vp) {                    /* loop over each trip */
        for (auto t2 : vp) {                /* 2nd search loop */
            if (t2.first == last) {         /* find trip begins with last city */
                total += "-" + t2.second;   /* add trip end to total */
                last = t2.second;           /* update last to end */
                break;                      /* go find next trip */
            }
        }
    }
    std::cout << '\n' << total << '\n';     /* output total trip beg to end */

( примечание: первый объект в каждом std::pair доступен с помощью .first, а второй с помощью .second - даже несколько логично ...)

Там Есть много вариантов, которые вы можете придумать. В целом, вы можете сделать:

#include <iostream>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

int main (void) {

    std::string home, last, trip, total;    /* strings */
    std::vector<std::pair<std::string, std::string>> vp {}; /* vector of pairs */

    std::cout << "enter home city: ";       /* prompt for home city */
    if (!getline (std::cin, home)) {        /* read/validate home city */
        std::cerr << "error: failed to read home-city.\n";
        return 1;
    }

    /* prompt for trips (any number of legs per-line), ENTER alone when done */
    std::cout << "\nenter trips (format city1-city2[-cityN]) "
                    "[Enter] alone when done\n\ntrip: ";
    while (getline (std::cin, trip)) {      /* while trip entered */
        if (!trip.length())                 /* if empty (zero length) break */
            break;
        std::stringstream ss (trip);        /* create stringsteam from line */
        std::string from, to;               /* strings for from and to cities */
        if (getline (ss, from, '-')) {      /* get from city from stringstrem */
            while (getline (ss, to, '-')) { /* get to city from stringstream */
                vp.push_back(std::make_pair (from, to));  /* add pair to vector */
                from = to;                  /* update from = to */
            }
        }
        std::cout << "trip: ";              /* prompt for next trip */
    }

    total = home;                           /* initialize total & last to home */
    last = home;
    for (auto t1 : vp) {                    /* loop over each trip */
        for (auto t2 : vp) {                /* 2nd search loop */
            if (t2.first == last) {         /* find trip begins with last city */
                total += "-" + t2.second;   /* add trip end to total */
                last = t2.second;           /* update last to end */
                break;                      /* go find next trip */
            }
        }
    }
    std::cout << '\n' << total << '\n';     /* output total trip beg to end */
}

Пример использования / Вывод

$ ./bin/triptotal
enter home city: Paris

enter trips (format city1-city2[-cityN]) [Enter] alone when done

trip: Berlin-Paris
trip: Paris-New York
trip: New York-Zagreb
trip: Ljubljana-Berlin
trip: Zagreb-Ljubljana
trip:

Paris-New York-Zagreb-Ljubljana-Berlin-Paris

Это также можно ввести как:

$ ./bin/triptotal
enter home city: Paris

enter trips (format city1-city2[-cityN]) [Enter] alone when done

trip: San Antonio-New York-Berlin-Paris
trip: Paris-Frankfort-Zagreb
trip: Zagreb-Ljubljana-Dallas
trip: Dallas-San Antonio
trip:

Paris-Frankfort-Zagreb-Ljubljana-Dallas-San Antonio-New York-Berlin-Paris

Еще одна ваша задача - найти способ справиться с несколькими этапами поездки, которые могут посетить один и тот же город. (это тоже оставлено для вас) Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 19 января 2020

Теперь мой вопрос: есть ли простой способ сделать это с 2+ адресными городами, такими как Нью-Йорк?

Да, это должно иметь тот же эффект, но позволяет 2 + слова города:

#include <iostream>
#include <string>
using namespace std;
string s[1000],city;
int n;  

int main(){
    string nStr;
    getline(cin, nStr);
    // converting string input to an integer
    n = stoi(nStr);
    getline(cin, city);
    for(int i=0;i<n;i++){
        getline(cin, s[i]);
    }
    cout<<city;
    for(int j=0;j<n;j++){
        for(int i=0;i<n;i++){
            if(s[i].substr(0,city.length())==city){
                city=s[i].substr(city.length()+1);
            cout<<"-"<<city;
            s[i]='\0';
            }   
        }   
    }
}

Ввод:
5
Париж
Берлин-Нью-Йорк
Париж-Загреб
Любляна-Берлин
Загреб-Любляна
Нью-Йорк-Париж

Вывод:
Париж-Загреб-Любляна-Берлин-Нью-Йорк-Париж

Я думал, что это должно вывести название города, но это это не тот случай, может кто-нибудь объяснить, почему?

Этот ответ объясняет, что cin помещает в поток символ новой строки, который getline немедленно читает в city и печатает перевод строки и так выглядит, как будто ничего не происходит.

...