Advertisement
RobertDeMilo

Используем для обработки ошибок коды возврата

Nov 3rd, 2023
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 18.38 KB | None | 0 0
  1. #include <algorithm>
  2. #include <cmath>
  3. #include <iostream>
  4. #include <map>
  5. #include <set>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9.  
  10. using namespace std;
  11.  
  12. const int MAX_RESULT_DOCUMENT_COUNT = 5;
  13.  
  14. //*********************************************************************************************************
  15. template <typename First, typename Second>
  16. ostream& operator<<(ostream& out, const pair<First, Second>& p) {
  17.     return out << p.first << ": "s << p.second;
  18. }
  19. //*********************************************************************************************************
  20. template <typename Container>
  21. void Print(ostream& out, const Container& container) {
  22.     bool is_first = true;
  23.     for (const auto& element : container) {
  24.         if (!is_first) {
  25.             out << ", "s;
  26.         }
  27.         is_first = false;
  28.         out << element;
  29.     }
  30. }
  31. //*********************************************************************************************************
  32. template <typename Element>
  33. ostream& operator<<(ostream& out, const vector<Element>& container) {
  34.     out << '[';
  35.     Print(out, container);
  36.     out << ']';
  37.     return out;
  38. }
  39. //*********************************************************************************************************
  40. template <typename Element>
  41. ostream& operator<<(ostream& out, const set<Element>& container) {
  42.     out << '{';
  43.     Print(out, container);
  44.     out << '}';
  45.     return out;
  46. }
  47. //*********************************************************************************************************
  48. template <typename Key, typename Value>
  49. ostream& operator<<(ostream& out, const map<Key, Value>& container) {
  50.     out << '{';
  51.     Print(out, container);
  52.     out << '}';
  53.     return out;
  54. }
  55. //###################################################################################################################
  56. template <typename T, typename U>
  57. void AssertEqualImpl(const T& t, const U& u, const string& t_str, const string& u_str, const string& file,
  58.     const string& func, unsigned line, const string& hint) {
  59.     if (t != u) {
  60.         cout << boolalpha;
  61.         cout << file << "("s << line << "): "s << func << ": "s;
  62.         cout << "ASSERT_EQUAL("s << t_str << ", "s << u_str << ") failed: "s;
  63.         cout << t << " != "s << u << "."s;
  64.         if (!hint.empty()) {
  65.             cout << " Hint: "s << hint;
  66.         }
  67.         cout << endl;
  68.         abort();
  69.     }
  70. }
  71. //#####################################################################################################################
  72. #define ASSERT_EQUAL(a, b) AssertEqualImpl((a), (b), #a, #b, __FILE__, __FUNCTION__, __LINE__, ""s)
  73.  
  74. #define ASSERT_EQUAL_HINT(a, b, hint) AssertEqualImpl((a), (b), #a, #b, __FILE__, __FUNCTION__, __LINE__, (hint))
  75. //#####################################################################################################################
  76.  
  77. void AssertImpl(bool value, const string& expr_str, const string& file, const string& func, unsigned line,
  78.     const string& hint) {
  79.     if (!value) {
  80.         cout << file << "("s << line << "): "s << func << ": "s;
  81.         cout << "ASSERT("s << expr_str << ") failed."s;
  82.         if (!hint.empty()) {
  83.             cout << " Hint: "s << hint;
  84.         }
  85.         cout << endl;
  86.         abort();
  87.     }
  88. }
  89. //#####################################################################################################################
  90. #define ASSERT(expr) AssertImpl(!!(expr), #expr, __FILE__, __FUNCTION__, __LINE__, ""s)
  91.  
  92. #define ASSERT_HINT(expr, hint) AssertImpl(!!(expr), #expr, __FILE__, __FUNCTION__, __LINE__, (hint))
  93. //#####################################################################################################################
  94.  
  95. string ReadLine() {
  96.     string s;
  97.     getline(cin, s);
  98.     return s;
  99. }
  100.  
  101. int ReadLineWithNumber() {
  102.     int result;
  103.     cin >> result;
  104.     ReadLine();
  105.     return result;
  106. }
  107.  
  108. vector<string> SplitIntoWords(const string& text) {
  109.     vector<string> words;
  110.     string word;
  111.     for (const char c : text) {
  112.         if (c == ' ') {
  113.             if (!word.empty()) {
  114.                 words.push_back(word);
  115.                 word.clear();
  116.             }
  117.         }
  118.         else {
  119.             word += c;
  120.         }
  121.     }
  122.     if (!word.empty()) {
  123.         words.push_back(word);
  124.     }
  125.  
  126.     return words;
  127. }
  128.  
  129. struct Document
  130. {
  131.     Document() = default;
  132.  
  133.     Document(int id, double relevance, int rating)
  134.         : id(id)
  135.         , relevance(relevance)
  136.         , rating(rating)
  137.         {}
  138.  
  139.     int id = 0;
  140.     double relevance = 0.0;
  141.     int rating = 0;
  142. };
  143.  
  144. template <typename StringContainer>
  145. set<string> MakeUniqueNonEmptyStrings(const StringContainer& strings) {
  146.     set<string> non_empty_strings;
  147.     for (const string& str : strings) {
  148.         if (!str.empty()) {
  149.             non_empty_strings.insert(str);
  150.         }
  151.     }
  152.     return non_empty_strings;
  153. }
  154.  
  155. enum class DocumentStatus {
  156.     ACTUAL,
  157.     IRRELEVANT,
  158.     BANNED,
  159.     REMOVED,
  160. };
  161.  
  162. class SearchServer {
  163. public:
  164.     template <typename StringContainer>
  165.     explicit SearchServer(const StringContainer& stop_words)
  166.         : stop_words_(MakeUniqueNonEmptyStrings(stop_words)) {
  167.     }
  168.  
  169.     explicit SearchServer(const string& stop_words_text)
  170.         : SearchServer(
  171.             SplitIntoWords(stop_words_text))  // Invoke delegating constructor from string container
  172.     {
  173.     }
  174.  
  175.     /*void AddDocument(int document_id, const string& document, DocumentStatus status,
  176.         const vector<int>& ratings)
  177.         {
  178.         const vector<string> words = SplitIntoWordsNoStop(document);
  179.         const double inv_word_count = 1.0 / words.size();
  180.         for (const string& word : words) {
  181.             word_to_document_freqs_[word][document_id] += inv_word_count;
  182.         }
  183.         documents_.emplace(document_id, DocumentData{ ComputeAverageRating(ratings), status });
  184.     }*/
  185.  
  186.     [[nodiscard]] bool AddDocument(int document_id, const string& document, DocumentStatus status,
  187.         const vector<int>& ratings)
  188.     {
  189.  
  190.         // negative id
  191.         if (document_id < 0)
  192.         {
  193.             return false;
  194.         }
  195.         // repeated id  
  196.         if (documents_.count(document_id) != 0)
  197.         {
  198.             return false;
  199.         }
  200.         // special symbol
  201.         if (any_of(document.begin(), document.end(), [](const char& c)
  202.             { return c >= 0 && c <= 31; }))
  203.         {
  204.             return false;
  205.         }
  206.  
  207.         const vector<string> words = SplitIntoWordsNoStop(document);
  208.         const double inv_word_count = 1.0 / words.size();
  209.         for (const string& word : words) {
  210.             word_to_document_freqs_[word][document_id] += inv_word_count;
  211.         }
  212.         documents_.emplace(document_id, DocumentData{ ComputeAverageRating(ratings), status });
  213.         ids_.push_back(document_id);
  214.  
  215.         return true;
  216.     }
  217.  
  218.     /*template <typename DocumentPredicate>
  219.     vector<Document> FindTopDocuments(const string& raw_query,
  220.         DocumentPredicate document_predicate) const
  221.         {
  222.         const Query query = ParseQuery(raw_query);
  223.         auto matched_documents = FindAllDocuments(query, document_predicate);
  224.  
  225.         sort(matched_documents.begin(), matched_documents.end(),
  226.             [](const Document& lhs, const Document& rhs) {
  227.                 if (abs(lhs.relevance - rhs.relevance) < 1e-6) {
  228.                     return lhs.rating > rhs.rating;
  229.                 }
  230.                 else {
  231.                     return lhs.relevance > rhs.relevance;
  232.                 }
  233.             });
  234.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  235.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  236.         }
  237.         return matched_documents;
  238.     }
  239.  
  240.     vector<Document> FindTopDocuments(const string& raw_query, DocumentStatus status) const {
  241.         return FindTopDocuments(
  242.             raw_query, [status](int document_id, DocumentStatus document_status, int rating) {
  243.                 return document_status == status;
  244.             });
  245.     }
  246.  
  247.     vector<Document> FindTopDocuments(const string& raw_query) const {
  248.         return FindTopDocuments(raw_query, DocumentStatus::ACTUAL);
  249.     }*/
  250.  
  251.     template <typename DocumentPredicate>
  252.     [[nodiscard]] bool FindTopDocuments(const string& raw_query, DocumentPredicate document_predicate, vector<Document>& result) const
  253.     {
  254.         // special symbol
  255.         if (any_of(raw_query.begin(), raw_query.end(), [](const char& c)
  256.             { return c >= 0 && c <= 31; }))
  257.         {
  258.             return false;
  259.         }
  260.  
  261.         Query query;
  262.         //const Query query = ParseQuery(raw_query);
  263.         if (!ParseQuery(raw_query, query))
  264.         {
  265.  
  266.             return false;
  267.         }
  268.  
  269.         result = FindAllDocuments(query, document_predicate);
  270.  
  271.         sort(result.begin(), result.end(),
  272.             [](const Document& lhs, const Document& rhs) {
  273.                 if (abs(lhs.relevance - rhs.relevance) < 1e-6) {
  274.                     return lhs.rating > rhs.rating;
  275.                 }
  276.                 else {
  277.                     return lhs.relevance > rhs.relevance;
  278.                 }
  279.             });
  280.         if (result.size() > MAX_RESULT_DOCUMENT_COUNT) {
  281.             result.resize(MAX_RESULT_DOCUMENT_COUNT);
  282.         }
  283.         //return matched_documents;
  284.         return true;
  285.     }
  286.  
  287.     [[nodiscard]] bool FindTopDocuments(const string& raw_query, DocumentStatus status, vector<Document>& result) const
  288.     {
  289.         return FindTopDocuments(
  290.             raw_query, [status](int document_id, DocumentStatus document_status, int rating) {
  291.                 return document_status == status; }, result);
  292.     }
  293.     [[nodiscard]] bool FindTopDocuments(const string& raw_query, vector<Document>& result) const
  294.     {
  295.         return FindTopDocuments(raw_query, DocumentStatus::ACTUAL, result);
  296.     }
  297.  
  298.     int GetDocumentCount() const {
  299.         return documents_.size();
  300.     }
  301.  
  302.     /*tuple<vector<string>, DocumentStatus> MatchDocument(const string& raw_query,
  303.         int document_id) const
  304.         {
  305.         const Query query = ParseQuery(raw_query);
  306.         vector<string> matched_words;
  307.         for (const string& word : query.plus_words) {
  308.             if (word_to_document_freqs_.count(word) == 0) {
  309.                 continue;
  310.             }
  311.             if (word_to_document_freqs_.at(word).count(document_id)) {
  312.                 matched_words.push_back(word);
  313.             }
  314.         }
  315.         for (const string& word : query.minus_words) {
  316.             if (word_to_document_freqs_.count(word) == 0) {
  317.                 continue;
  318.             }
  319.             if (word_to_document_freqs_.at(word).count(document_id)) {
  320.                 matched_words.clear();
  321.                 break;
  322.             }
  323.         }
  324.         return { matched_words, documents_.at(document_id).status };
  325.     }*/
  326.     [[nodiscard]] bool MatchDocument(const string& raw_query, int document_id,
  327.         tuple<vector<string>, DocumentStatus>& result) const
  328.     {
  329.         // special symbol
  330.         if (any_of(raw_query.begin(), raw_query.end(), [](const char& c)
  331.             { return c >= 0 && c <= 31; }))
  332.         {
  333.             return false;
  334.         }
  335.  
  336.         Query query;
  337.         if (!ParseQuery(raw_query, query))
  338.         {
  339.             return false;
  340.         }
  341.  
  342.         vector<string> matched_words;
  343.  
  344.         for (const string& word : query.plus_words) {
  345.             if (word_to_document_freqs_.count(word) == 0) {
  346.                 continue;
  347.             }
  348.             if (word_to_document_freqs_.at(word).count(document_id)) {
  349.                 matched_words.push_back(word);
  350.             }
  351.         }
  352.         for (const string& word : query.minus_words) {
  353.             if (word_to_document_freqs_.count(word) == 0) {
  354.                 continue;
  355.             }
  356.             if (word_to_document_freqs_.at(word).count(document_id)) {
  357.                 matched_words.clear();
  358.                 break;
  359.             }
  360.         }
  361.         result = { matched_words, documents_.at(document_id).status };
  362.         return true;
  363.         // return { matched_words, documents_.at(document_id).status };
  364.     }
  365.  
  366.  
  367.     int GetDocumentId(int index) const
  368.     {
  369.         if (index > documents_.size() && index < 0)
  370.         {
  371.             return SearchServer::INVALID_DOCUMENT_ID;
  372.         }
  373.         return ids_[index];
  374.     }
  375.     // Также добавьте метод GetDocumentId, позволяющий получить идентификатор документа по его порядковому номеру.
  376.     // В случае, если порядковый номер документа выходит за пределы от[0; кол - во документов), метод должен
  377.     // вернуть значение SearchServer::INVALID_DOCUMENT_ID:
  378.  
  379. private:
  380.     inline static constexpr int INVALID_DOCUMENT_ID = -1;
  381.  
  382.     struct DocumentData
  383.     {
  384.         int rating;
  385.         DocumentStatus status;
  386.     };
  387.  
  388.     struct QueryWord
  389.     {
  390.         string data;
  391.         bool is_minus;
  392.         bool is_stop;
  393.     };
  394.  
  395.     struct Query
  396.     {
  397.         set<string> plus_words;
  398.         set<string> minus_words;
  399.     };
  400.  
  401.     const set<string> stop_words_;
  402.  
  403.     map<string, map<int, double>> word_to_document_freqs_;
  404.     vector <int> ids_;
  405.  
  406.     map<int, DocumentData> documents_;
  407.  
  408.     bool IsStopWord(const string& word) const
  409.     {
  410.         return stop_words_.count(word) > 0;
  411.     }
  412.  
  413.     vector<string> SplitIntoWordsNoStop(const string& text) const {
  414.         vector<string> words;
  415.         for (const string& word : SplitIntoWords(text)) {
  416.             if (!IsStopWord(word)) {
  417.                 words.push_back(word);
  418.             }
  419.         }
  420.         return words;
  421.     }
  422.  
  423.     static int ComputeAverageRating(const vector<int>& ratings) {
  424.         if (ratings.empty()) {
  425.             return 0;
  426.         }
  427.         int rating_sum = 0;
  428.         for (const int rating : ratings) {
  429.             rating_sum += rating;
  430.         }
  431.         return rating_sum / static_cast<int>(ratings.size());
  432.     }
  433.  
  434.     //QueryWord ParseQueryWord(string text) const {
  435.     //    bool is_minus = false;
  436.     //    // Word shouldn't be empty
  437.  
  438.     //    if (text[0] == '-') {
  439.     //        is_minus = true;
  440.     //        text = text.substr(1);
  441.     //    }
  442.     //    return { text, is_minus, IsStopWord(text) };
  443.     //}
  444.  
  445.  
  446.  
  447.     //Query ParseQuery(const string& text) const
  448.     bool ParseQuery(const string& text, Query& query) const
  449.     {
  450.  
  451.         for (const string& word : SplitIntoWordsNoStop(text))
  452.         {
  453.             if (SplitIntoWordsNoStop(text).back() == "-")
  454.             {
  455.                 return false;
  456.             }
  457.  
  458.             if (int not_minus_pos = word.find_first_not_of('-'); not_minus_pos >= 2)
  459.             {
  460.                 return false;
  461.             }
  462.             else if (word[0] == '-')
  463.             {
  464.                 query.minus_words.insert(word.substr(1));
  465.             }
  466.             else
  467.             {
  468.                 query.plus_words.insert(word);
  469.             }
  470.         }
  471.         return true;
  472.         //return query;
  473.     }
  474.  
  475.     // Existence required
  476.     double ComputeWordInverseDocumentFreq(const string& word) const {
  477.         return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  478.     }
  479.  
  480.     template <typename DocumentPredicate>
  481.     vector<Document> FindAllDocuments(const Query& query,
  482.         DocumentPredicate document_predicate) const {
  483.         map<int, double> document_to_relevance;
  484.         for (const string& word : query.plus_words) {
  485.             if (word_to_document_freqs_.count(word) == 0) {
  486.                 continue;
  487.             }
  488.             const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  489.             for (const auto [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  490.                 const auto& document_data = documents_.at(document_id);
  491.                 if (document_predicate(document_id, document_data.status, document_data.rating)) {
  492.                     document_to_relevance[document_id] += term_freq * inverse_document_freq;
  493.                 }
  494.             }
  495.         }
  496.  
  497.         for (const string& word : query.minus_words) {
  498.             if (word_to_document_freqs_.count(word) == 0) {
  499.                 continue;
  500.             }
  501.             for (const auto [document_id, _] : word_to_document_freqs_.at(word)) {
  502.                 document_to_relevance.erase(document_id);
  503.             }
  504.         }
  505.  
  506.         vector<Document> matched_documents;
  507.         for (const auto [document_id, relevance] : document_to_relevance) {
  508.             matched_documents.push_back(
  509.                 { document_id, relevance, documents_.at(document_id).rating });
  510.         }
  511.         return matched_documents;
  512.     }
  513. };
  514.  
  515. void TestAddDocument()
  516. {
  517.     setlocale(LC_ALL, "ru");
  518.     {
  519.         SearchServer search_server("и в на"s);
  520.         search_server.AddDocument(1, "пушистый кот пушистый хвост"s, DocumentStatus::ACTUAL, { 7, 2, 7 });
  521.         ASSERT(!search_server.AddDocument(1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, { 1, 2 }));
  522.     }
  523.     {
  524.         SearchServer search_server("и в на"s);
  525.         ASSERT(!search_server.AddDocument(-1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, { 1, 2 }));
  526.     }
  527.     {
  528.         SearchServer search_server("и в на"s);
  529.         ASSERT(!search_server.AddDocument(3, "большой пёс скво\x12рец"s, DocumentStatus::ACTUAL, { 1, 3, 2 }));
  530.     }
  531. }
  532. void TestFindTopDocuments()
  533. {
  534.     setlocale(LC_ALL, "ru");
  535.     SearchServer search_server("и в на"s);
  536.  
  537.     search_server.AddDocument(1, "пушистый кот пушистый хвост"s, DocumentStatus::ACTUAL, { 7, 2, 7 });
  538.     search_server.AddDocument(2, "белый пес с черным ухом"s, DocumentStatus::ACTUAL, { 10, 20, 30 });
  539.  
  540.     vector<Document> documents;
  541.  
  542.     ASSERT(!search_server.FindTopDocuments("большой кр\x12сивый"s, documents));
  543.     ASSERT(!search_server.FindTopDocuments("--пушистый"s, documents));
  544.     ASSERT(!search_server.FindTopDocuments("---пушистый"s, documents));
  545.     ASSERT(!search_server.FindTopDocuments("-красивый --пушистый"s, documents));
  546.     ASSERT(!search_server.FindTopDocuments("ошейник --пушистый"s, documents));
  547.     ASSERT(!search_server.FindTopDocuments("-иван-чай - -сова -   "s, documents));
  548.  
  549. }
  550.  
  551. class TestRunner
  552. {
  553. public:
  554.  
  555.     template <class TestFunc>
  556.     void RunTest(TestFunc func, const string& test_name)
  557.     {
  558.         try
  559.         {
  560.             func();
  561.             cerr << test_name << " OK" << endl;
  562.         }
  563.         catch (runtime_error& e)
  564.         {
  565.             ++fail_count;
  566.             cerr << test_name << " fail: " << e.what() << endl;
  567.         }
  568.  
  569.     }
  570.     ~TestRunner()
  571.     {
  572.         if (fail_count > 0)
  573.         {
  574.             cerr << fail_count << " tests failed. Terminate";
  575.             exit(1);
  576.         }
  577.     }
  578. private:
  579.  
  580.     int fail_count = 0;
  581. };
  582.  
  583. void TestAll()
  584. {
  585.     TestRunner tr;
  586.  
  587.     tr.RunTest(TestAddDocument, "TestAddDocument");
  588.     tr.RunTest(TestFindTopDocuments, "TestFindTopDocuments");
  589.  
  590. }
  591. // ==================== для примера =========================
  592.  
  593.  
  594. void PrintDocument(const Document& document) {
  595.     cout << "{ "s
  596.         << "document_id = "s << document.id << ", "s
  597.         << "relevance = "s << document.relevance << ", "s
  598.         << "rating = "s << document.rating << " }"s << endl;
  599. }
  600.  
  601. //###################################################################################################################
  602.  
  603. int main() {
  604.  
  605.     TestAll();
  606.  
  607.     setlocale(LC_ALL, "ru");
  608.  
  609.     SearchServer search_server("и в на"s);
  610.  
  611.     // Явно игнорируем результат метода AddDocument, чтобы избежать предупреждения
  612.     // о неиспользуемом результате его вызова
  613.  
  614.     (void)search_server.AddDocument(1, "пушистый кот пушистый хвост"s, DocumentStatus::ACTUAL, { 7, 2, 7 });
  615.  
  616.     if (!search_server.AddDocument(1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, { 1, 2 })) {
  617.         cout << "Документ не был добавлен, так как его id совпадает с уже имеющимся"s << endl;
  618.     }
  619.     if (!search_server.AddDocument(-1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, { 1, 2 })) {
  620.         cout << "Документ не был добавлен, так как его id отрицательный"s << endl;
  621.     }
  622.     if (!search_server.AddDocument(3, "большой пёс скво\x12рец"s, DocumentStatus::ACTUAL, { 1, 3, 2 })) {
  623.         cout << "Документ не был добавлен, так как содержит спецсимволы"s << endl;
  624.     }
  625.     vector<Document> documents;
  626.     if (search_server.FindTopDocuments("--пушистый"s, documents)) {
  627.         for (const Document& document : documents) {
  628.             PrintDocument(document);
  629.         }
  630.     }
  631.     else {
  632.         cout << "Ошибка в поисковом запросе"s << endl;
  633.     }
  634. }
  635.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement