Професионална програма
Loading...
Filipbg avatar Filipbg 26 Точки

Count Real Numbers

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

int main()
{
    string lineOfNumbers;
    getline(cin, lineOfNumbers);
    istringstream numbersStream(lineOfNumbers);
    vector<double> numbersVector(stod(lineOfNumbers));
    sort(numbersVector.begin(), numbersVector.end(), greater<double>());
    for(int i = 0; i < numbersVector.size(); ++i)
        cout << numbersVector.at(i) << " -> ";
    return 0;
}

Нещо ми се бърка от задачата. А пък и вектора ми занулява числата. Пробрах с pair от string and double, но ми гърми на getline да не би вместо да трябва да се сортират да трябва да се закрагляват с ceil? Несхващам описанието на задачата. 

 
0
C++ Fundamentals
dmartinov avatar dmartinov 36 Точки

Ммммм....нещо не виждам къде пълниш числата във вектора :) И тоя входен поток дето си създал.....не го ползваш никъде ;) Така както си го написал създаваш един вектор с n на брой елементи, които обаче не съдържат нищо.

Идеята на задачата е да получиш от конзолата някаква поредност от числа, да провериш колко пъти се появяват в тази поредност и накрая да принтираш този резултат във възходящ ред. 

Моят жокер за решаването е - разгледай внимателно лекцията, още в самото начало където Живко показа как се достъпва map и какво се случва ако търсеното value го няма.

0
19/10/2019 17:29:59
Filipbg avatar Filipbg 26 Точки

Гледах пак лекцията, макар че доста неща с map и pair ме объркват. Промених си подхода И се опитвам да съединя прочетеното число с брояч. За да намеря колко пъти го има в потока. Чете ми ги числата, но брояча не работи. 

#include <iostream>
#include <vector>
#include <algorithm>
#include <sstream>
#include <map>
using namespace std;

int main()
{
    map<double, int> numbersMap;
    string line;
    getline(cin, line);
    istringstream numbersStream(line);
    double numberToRead = 0;
    int counter = 0;
    while(numbersStream >> numberToRead)
    {
        numbersMap.insert(pair<double, int>(numberToRead, counter));
        if(numbersMap.find(numberToRead) != numbersMap.end())
        {
            ++counter;
        }
        else
        {
            cin >> numberToRead;
        }
    }
    for(pair<double, int>number : numbersMap)
    {
        cout << number.first << " -> " << number.second << endl;
    }
    return 0;
}

 

0
galin_kostadinov avatar galin_kostadinov 163 Точки

Привет!

Eто това е един работещ вариант:

Първо проверяваш дали елемента го няма, т.е. ако итератора ти върне numbersMap.end(), това означава, че вече си един елемент след този, който имаш последно записан в map, т.е. обходил си елемент по елемент map и нищо не е намерило, като ти връща numbersMap.end(). След което го добавяш със стойност 1, тъй като за сега само един път си го срещал. Ако след това пак имаш същата стойност, то итератора няма да ти върне numbersMap.end(), а ще ти върне итератор към съществуващата стойност.

if (numbersMap.find(numberToRead) == numbersMap.end()) {
    numbersMap.insert(pair<double, int>(numberToRead, 1));
} else {
    numbersMap[numberToRead]++;
}

- чрез този оператор [...] като използваш ключа numberToRead(в случая double), достъпваш до стойността (в случая int), но трябва да се внимава, понеже независимо дали има или няма записана стойност под този ключ, чрез този оператор директно се създава стойност(дефолтна за типа данни) и ключ(зададения).

- тъй като в случая се иска именно да се добави в map стойност, ако тя липсва е много удобно:

++numbersMap[numberToRead]; - така създаваш стойност ако липсва и увеличаваш дефолтната и стойност от 0 на 1 чрез ++[...].

Може да зададеш и някаква желана стойност(по прицип, в случая не ти трябва):

numbersMap[numberToRead] = 5;

Поздрави!

0
20/10/2019 14:57:59
dmartinov avatar dmartinov 36 Точки

Няма нужда да смесваш map и pair. Решението на задачата наистина е в слайда от лекцията за достъпването на map. Идеята е следната - когато се опиташ да достъпиш нещо от map което не се съдържа в него, то първо се създава след което връща неговата default стойност според типа зададен при създаване на map-a. Иначе казано ако имаш std::map<int, int> и ти потърсиш в него числото 1, но то не се съдъжра, то 1-цата ще влезе като ключ, а за value ще имаш default стойност 0 (защото сме създали map от интиджъри). Та този път си сравнително на прав път. Това което трябва да направиш е да махнеш pair-a. Усложнява ти излишно логиката. Махни и тези IF-ове. В while цикъла където подаваш входния поток към числата, които ще търсиш директно се опитвай да ги достъпваш в map-а. По този начин освен, че ще създадеш ключа в мap-а, както казахме по-горе, се възползваш и от другото много удобно за случая свойство на map - не може да създадеш един ключ два пъти, но пък ако вече го има само ще промениш неговото value. Накрая ти остава само да принтираш съдържанието на map-а.

Hint - още при първото създаване на ключа сетни value-то му на 1. В противен случай ако имаш елемента само веднъж накрая ще ти принтира 0.

Ето моето решение:

#include <iostream>
#include <string>
#include <map>
#include <sstream>

void countRealNumbers(std::string input) {

    double numbers = 0.0;
    std::istringstream iss (input);
    std::map<double, double> mapNumbers;

    while (iss >> numbers) {
        mapNumbers[numbers]++;
    }

    std::map<double, double>::iterator itr;

    for(itr = mapNumbers.begin(); itr != mapNumbers.end(); ++itr) {
        std::cout << itr -> first << " -> " << itr -> second << std::endl;
    }
}

int main() {

    std::string input;

    getline(std::cin, input);

    countRealNumbers(input);

    return 0;
}
 

0
Filipbg avatar Filipbg 26 Точки

Благодаря за подробния отговор и обяснението ти. Пробвах твоя вариянт, но поради някаква причина ми изкарва безкраен цикъл. За което не виждам поради каква причина става това, след като цикъла ми се състои от while(numbersStream >> numberToRead) докато можеш да извличаш double извличай. 

         cin >> numberToRead;
         if(numbersMap.find(numberToRead) == numbersMap.end())
         {
               numbersMap.insert(pair<double, int>(numberToRead, 1));
         }
         else
         {
              ++numbersMap[numberToRead];
         }

Смених местото на cin. Чудех се дали на добавя проверка за break, но в задачата няма end или някаква друга команда за приключване на четенето. Объркан съм :/

0
galin_kostadinov avatar galin_kostadinov 163 Точки

Привет!

Ето така трябва да изглежда, кода ти:

https://pastebin.com/48KAEiDB

Веднъж щом си взел входните данни, които по условие, ти се подават на един ред и заради това използваш:

getline(cin, line);

то повече не използва четене от конзолата, понеже няма какво повече да четеш:

cin >> numberToRead; - това го махни

След това си правиш стринг поток:

istringstream numbersStream(line);

от който след това четеш докато има какво да четеш:

while(numbersStream >> numberToRead){
...}

Ако нямаш какво да четеш от потока ще ти върне false и цикъла ще приключи.

Използайки istringstream и като му подадеш, конкретния стринг line, то този поток знае къде е краят му, докато потока от конзолата е постоянен, ако му кажеш да чете, ще иска да му въведеш стойност и да чете. Ако използваш

while(cin>> numberToRead){...}

то ще чете докато не възникне грешка при четeнето(т.е. тъй като очаква да му въведеш double, докато му въвешдаш число в цикъла ще се връща true, т.е. операцията е успеша, ако въведеш нещо различно от число, което се изисква в случая false).

Поздрави!

 

0
20/10/2019 15:38:01
Filipbg avatar Filipbg 26 Точки

galin_kostadinov Определено нямаше да се сетя, че cin ми пречи и е ненужен в случая. Като гледам че постоянно ще се чете поток от числа, не се замислих че getline цялостно го изчита. Дано да успея да се справя с останалите задачи до четвъртък. Благодаря ти за уточненията!

0
20/10/2019 19:01:54
Filipbg avatar Filipbg 26 Точки

dmartinov Твоето решение изглежда много кратко и логиката му е straight, аз от лекцията разбрах, че е задължителен този pair за да може map да се пълни докато са синхронизирани(асоцирани) променливите. Или може би погрешно разбирам контекста на "двойките" в даден map.

0
20/10/2019 18:41:58
dmartinov avatar dmartinov 36 Точки

Логиката която следва моето решение е много проста - създавам празен map. Oт входния поток който създавам започвам да извличам числата едно по едно и се опитвам да ги достъпя в map-а и понеже той е празен автоматично се създават като ключове и сетвам value-то на 1. И така за всяко следващо число, което извлека от потока. Ако някое от тях ги срещна втори път то няма да се запише защото този ключ вече го има, но ще се увеличи value-то. Когато вече нямам повече числа за извличане излизам от цикъла и ми остава само да печатам.

Точно това обясниха на лекцията и това се опитвам да ти обясня и аз - да, може да направиш pair който да мушкаш в map, като едната стойност от pair-a ще бъде key, a другата value. В случая моята логика е кратка и подходяща защото ни позволява да печатаме в правилната последователност, която искаме и освен това ще го ползваме да броим. Ние не искаме да търсим измежду вече зададени стойности. Ние директно му подаваме стойностие като при всяко подавне казваме ++ на брояча ни. Ако няма това което подаваме, то се записва и брояча става 1, ако го има той си казва "аха, аз го имам, моите ключове са уникални, няма как да го запиша втори път, но пък ти искаш щом го имам да му увеличим брояча, добре - брояча става 2" :)

P.S.: Колко дебилно звучи когато се опитваш да говориш от името на компютъра, но пък си представяш какво се случва в "главата" му, което е яко :) 

0