Advertisement
AlexDanilin

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

Jun 16th, 2023
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.13 KB | None | 0 0
  1. //Урок 2: Используем для обработки ошибок коды возврата
  2. #include <algorithm>
  3. #include <cmath>
  4. #include <iostream>
  5. #include <map>
  6. #include <set>
  7. #include <string>
  8. #include <utility>
  9. #include <vector>
  10.  
  11. using namespace std;
  12.  
  13. const int MAX_RESULT_DOCUMENT_COUNT = 5;
  14.  
  15. string ReadLine() {
  16.     string s;
  17.     getline(cin, s);
  18.     return s;
  19. }
  20.  
  21. int ReadLineWithNumber() {
  22.     int result;
  23.     cin >> result;
  24.     ReadLine();
  25.     return result;
  26. }
  27.  
  28. vector<string> SplitIntoWords(const string& text) {
  29.     vector<string> words;
  30.     string word;
  31.     for (const char c : text) {
  32.         if (c == ' ') {
  33.             if (!word.empty()) {
  34.                 words.push_back(word);
  35.                 word.clear();
  36.             }
  37.         } else {
  38.             word += c;
  39.         }
  40.     }
  41.     if (!word.empty()) {
  42.         words.push_back(word);
  43.     }
  44.  
  45.     return words;
  46. }
  47.  
  48. struct Document {
  49.     Document() = default;
  50.  
  51.     Document(int id, double relevance, int rating)
  52.         : id(id)
  53.         , relevance(relevance)
  54.         , rating(rating) {
  55.     }
  56.  
  57.     int id = 0;
  58.     double relevance = 0.0;
  59.     int rating = 0;
  60. };
  61.  
  62. template <typename StringContainer>
  63. set<string> MakeUniqueNonEmptyStrings(const StringContainer& strings) {
  64.     set<string> non_empty_strings;
  65.     for (const string& str : strings) {
  66.         if (!str.empty()) {
  67.             non_empty_strings.insert(str);
  68.         }
  69.     }
  70.     return non_empty_strings;
  71. }
  72.  
  73. enum class DocumentStatus {
  74.     ACTUAL,
  75.     IRRELEVANT,
  76.     BANNED,
  77.     REMOVED,
  78. };
  79.  
  80. class SearchServer {
  81. public:
  82.    
  83.     // Defines an invalid document id
  84.     // You can refer to this constant as SearchServer::INVALID_DOCUMENT_ID
  85.     inline static constexpr int INVALID_DOCUMENT_ID = -1;
  86.     SearchServer() = default;
  87.    
  88.     template <typename StringContainer>
  89.     explicit SearchServer(const StringContainer& stop_words)
  90.         : stop_words_(MakeUniqueNonEmptyStrings(stop_words)) {
  91.     }
  92.  
  93.     explicit SearchServer(const string& stop_words_text)
  94.         : SearchServer(
  95.             SplitIntoWords(stop_words_text))  // Invoke delegating constructor from string container
  96.     {
  97.     }
  98.    
  99.      [[nodiscard]] bool AddDocument(int document_id, const string& document, DocumentStatus status, const vector<int>& ratings) {
  100.         if (document_id < 0) {
  101.             return false;
  102.         }
  103.         if (documents_.find(document_id) != documents_.end()) {
  104.             return false;
  105.         }
  106.  
  107.         const vector<string> words = SplitIntoWordsNoStop(document);
  108.         for (auto& word : words) {
  109.             if (!IsValidWord(word)) {
  110.                 return false;
  111.             }
  112.         }
  113.         for (auto& word : words) {
  114.             word_to_document_freqs_[word][document_id] += 1.0 / words.size();
  115.         }
  116.         documents_.emplace(document_id, DocumentData { ComputeAverageRating(ratings), status });
  117.         documents_index_.push_back(document_id);
  118.  
  119.         return true;
  120.     }
  121.    
  122.    
  123.    
  124. /*
  125.     void AddDocument(int document_id, const string& document, DocumentStatus status,
  126.                      const vector<int>& ratings) {
  127.         const vector<string> words = SplitIntoWordsNoStop(document);
  128.         const double inv_word_count = 1.0 / words.size();
  129.         for (const string& word : words) {
  130.             word_to_document_freqs_[word][document_id] += inv_word_count;
  131.         }
  132.         documents_.emplace(document_id, DocumentData{ComputeAverageRating(ratings), status});
  133.     }*/
  134.    
  135.  
  136.     template <typename DocumentPredicate>
  137.     /*
  138.     vector<Document> FindTopDocuments(const string& raw_query,
  139.                                       DocumentPredicate document_predicate) const {
  140.         const Query query = ParseQuery(raw_query);
  141.         auto matched_documents = FindAllDocuments(query, document_predicate);
  142.  
  143.         sort(matched_documents.begin(), matched_documents.end(),
  144.              [](const Document& lhs, const Document& rhs) {
  145.                  if (abs(lhs.relevance - rhs.relevance) < 1e-6) {
  146.                      return lhs.rating > rhs.rating;
  147.                  } else {
  148.                      return lhs.relevance > rhs.relevance;
  149.                  }
  150.              });
  151.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  152.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  153.         }
  154.         return matched_documents;
  155.     }
  156.  
  157.     vector<Document> FindTopDocuments(const string& raw_query, DocumentStatus status) const {
  158.         return FindTopDocuments(
  159.             raw_query, [status](int document_id, DocumentStatus document_status, int rating) {
  160.                 return document_status == status;
  161.             });
  162.     }
  163.  
  164.     vector<Document> FindTopDocuments(const string& raw_query) const {
  165.         return FindTopDocuments(raw_query, DocumentStatus::ACTUAL);
  166.     }*/
  167.    
  168.     [[nodiscard]] bool FindTopDocuments(const string& raw_query, DocumentPredicate document_predicate, vector<Document>& result) const {
  169.         if (raw_query.empty()) {
  170.             return false;
  171.         }
  172.  
  173.         for (const string& word : SplitIntoWords(raw_query)) {
  174.             if (!IsValidWord(word)) {
  175.                 return false;
  176.             }
  177.             if (!IsValidMinusWord(word)) {
  178.                 return false;
  179.             }
  180.         }
  181.  
  182.         const Query query = ParseQuery(raw_query);
  183.         auto matched_documents = FindAllDocuments(query, document_predicate);
  184.  
  185.         sort(matched_documents.begin(), matched_documents.end(),
  186.             [](const Document& lhs, const Document& rhs) {
  187.                 const double EPSILON = 1e-6;
  188.                 if (abs(lhs.relevance - rhs.relevance) < EPSILON) {
  189.                     return lhs.rating > rhs.rating;
  190.                 }
  191.                 else {
  192.                     return lhs.relevance > rhs.relevance;
  193.                 }
  194.             });
  195.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  196.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  197.         }
  198.  
  199.         result = matched_documents;
  200.         return true;
  201.     }
  202.    
  203.    
  204.     [[nodiscard]] bool FindTopDocuments(const string& raw_query, DocumentStatus status, vector<Document>& result) const {
  205.         return FindTopDocuments(raw_query,
  206.             [&status](int document_id, DocumentStatus new_status, int rating) {
  207.                 return new_status == status;
  208.             }, result);
  209.     }
  210.    
  211.      [[nodiscard]] bool FindTopDocuments(const string& raw_query, vector<Document>& result) const {
  212.         return FindTopDocuments(raw_query, DocumentStatus::ACTUAL, result);
  213.     }
  214.    
  215.    
  216.  
  217.    
  218.     int GetDocumentCount() const {
  219.         return static_cast<int>(documents_.size());
  220.     }
  221.    
  222. /*
  223.     tuple<vector<string>, DocumentStatus> MatchDocument(const string& raw_query,
  224.                                                         int document_id) const {
  225.         const Query query = ParseQuery(raw_query);
  226.         vector<string> matched_words;
  227.         for (const string& word : query.plus_words) {
  228.             if (word_to_document_freqs_.count(word) == 0) {
  229.                 continue;
  230.             }
  231.             if (word_to_document_freqs_.at(word).count(document_id)) {
  232.                 matched_words.push_back(word);
  233.             }
  234.         }
  235.         for (const string& word : query.minus_words) {
  236.             if (word_to_document_freqs_.count(word) == 0) {
  237.                 continue;
  238.             }
  239.             if (word_to_document_freqs_.at(word).count(document_id)) {
  240.                 matched_words.clear();
  241.                 break;
  242.             }
  243.         }
  244.         return {matched_words, documents_.at(document_id).status};
  245.     }*/
  246.      [[nodiscard]] bool MatchDocument(const string& raw_query, int document_id, tuple<vector<string>, DocumentStatus>& result) const {
  247.         if (raw_query.empty()) {
  248.             return false;
  249.         }
  250.  
  251.         for (const string& word : SplitIntoWords(raw_query)) {
  252.             if (!IsValidWord(word)) {
  253.                 return false;
  254.             }
  255.             if (!IsValidMinusWord(word)) {
  256.                 return false;
  257.             }
  258.         }
  259.  
  260.         const Query query = ParseQuery(raw_query);
  261.         vector<string> matched_words;
  262.         for (const string& word : query.plus_words) {
  263.             if (word_to_document_freqs_.count(word) == 0) {
  264.                 continue;
  265.             }
  266.             if (word_to_document_freqs_.at(word).count(document_id)) {
  267.                 matched_words.push_back(word);
  268.             }
  269.         }
  270.         for (const string& word : query.minus_words) {
  271.             if (word_to_document_freqs_.count(word) == 0) {
  272.                 continue;
  273.             }
  274.             if (word_to_document_freqs_.at(word).count(document_id)) {
  275.                 matched_words.clear();
  276.                 break;
  277.             }
  278.         }
  279.  
  280.         result = { matched_words, documents_.at(document_id).status };
  281.         return true;
  282.     }
  283.    
  284.     int GetDocumentId(int index) const {
  285.         if ((index >= 0) && (index < static_cast<int>(documents_.size()))) {
  286.             return documents_index_[index];
  287.         }
  288.         return SearchServer::INVALID_DOCUMENT_ID;
  289.     }
  290.  
  291.    
  292.    
  293.    
  294. private:
  295.    
  296.    
  297.     struct DocumentData {
  298.         int rating;
  299.         DocumentStatus status;
  300.     };
  301.     const set<string> stop_words_;
  302.     map<string, map<int, double>> word_to_document_freqs_;
  303.     map<int, DocumentData> documents_;
  304.     vector<int> documents_index_;
  305.  
  306.     bool IsStopWord(const string& word) const {
  307.         return stop_words_.count(word) > 0;
  308.     }
  309.    
  310.     static bool IsValidWord(const string& word) {
  311.         // A valid word must not contain special characters
  312.         return none_of(word.begin(), word.end(), [](char c) {
  313.             return c >= '\0' && c < ' ';
  314.         });
  315.     }
  316.    
  317.      static bool IsValidMinusWord(const string& word) {
  318.         if (word.empty()) {
  319.             return false;
  320.         }
  321.         if (word == "-"s) {
  322.             return false;
  323.         }
  324.         if (word[0] == '-' && word[1] == '-') {
  325.             return false;
  326.         }
  327.          return true;
  328.     }
  329.    
  330.    
  331.  
  332.     vector<string> SplitIntoWordsNoStop(const string& text) const {
  333.         vector<string> words;
  334.         for (const string& word : SplitIntoWords(text)) {
  335.             if (!IsStopWord(word)) {
  336.                 words.push_back(word);
  337.             }
  338.         }
  339.         return words;
  340.     }
  341.  
  342.     static int ComputeAverageRating(const vector<int>& ratings) {
  343.         if (ratings.empty()) {
  344.             return 0;
  345.         }
  346.         int rating_sum = 0;
  347.         for (const int rating : ratings) {
  348.             rating_sum += rating;
  349.         }
  350.         return rating_sum / static_cast<int>(ratings.size());
  351.     }
  352.  
  353.     struct QueryWord {
  354.         string data;
  355.         bool is_minus;
  356.         bool is_stop;
  357.     };
  358.  
  359.     QueryWord ParseQueryWord(string text) const {
  360.         bool is_minus = false;
  361.         // Word shouldn't be empty
  362.         if (text[0] == '-') {
  363.             is_minus = true;
  364.             text = text.substr(1);
  365.         }
  366.         return {text, is_minus, IsStopWord(text)};
  367.     }
  368.  
  369.     struct Query {
  370.         set<string> plus_words;
  371.         set<string> minus_words;
  372.     };
  373.  
  374.     Query ParseQuery(const string& text) const {
  375.         Query query;
  376.         for (const string& word : SplitIntoWords(text)) {
  377.             const QueryWord query_word = ParseQueryWord(word);
  378.             if (!query_word.is_stop) {
  379.                 if (query_word.is_minus) {
  380.                     query.minus_words.insert(query_word.data);
  381.                 } else {
  382.                     query.plus_words.insert(query_word.data);
  383.                 }
  384.             }
  385.         }
  386.         return query;
  387.     }
  388.  
  389.     // Existence required
  390.     double ComputeWordInverseDocumentFreq(const string& word) const {
  391.         return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  392.     }
  393.  
  394.     template <typename DocumentPredicate>
  395.     vector<Document> FindAllDocuments(const Query& query,
  396.                                       DocumentPredicate document_predicate) const {
  397.         map<int, double> document_to_relevance;
  398.         for (const string& word : query.plus_words) {
  399.             if (word_to_document_freqs_.count(word) == 0) {
  400.                 continue;
  401.             }
  402.             const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  403.             for (const auto [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  404.                 const auto& document_data = documents_.at(document_id);
  405.                 if (document_predicate(document_id, document_data.status, document_data.rating)) {
  406.                     document_to_relevance[document_id] += term_freq * inverse_document_freq;
  407.                 }
  408.             }
  409.         }
  410.  
  411.         for (const string& word : query.minus_words) {
  412.             if (word_to_document_freqs_.count(word) == 0) {
  413.                 continue;
  414.             }
  415.             for (const auto [document_id, _] : word_to_document_freqs_.at(word)) {
  416.                 document_to_relevance.erase(document_id);
  417.             }
  418.         }
  419.  
  420.         vector<Document> matched_documents;
  421.         for (const auto [document_id, relevance] : document_to_relevance) {
  422.             matched_documents.push_back(
  423.                 {document_id, relevance, documents_.at(document_id).rating});
  424.         }
  425.         return matched_documents;
  426.     }
  427. };
  428.  
  429. // ==================== для примера =========================
  430.  
  431. void PrintDocument(const Document& document) {
  432.     cout << "{ "s
  433.          << "document_id = "s << document.id << ", "s
  434.          << "relevance = "s << document.relevance << ", "s
  435.          << "rating = "s << document.rating << " }"s << endl;
  436. }
  437. int main() {
  438.     SearchServer search_server("и в на"s);
  439.     // Явно игнорируем результат метода AddDocument, чтобы избежать предупреждения
  440.     // о неиспользуемом результате его вызова
  441.     (void) search_server.AddDocument(1, "пушистый кот пушистый хвост"s, DocumentStatus::ACTUAL, {7, 2, 7});
  442.     if (!search_server.AddDocument(1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, {1, 2})) {
  443.         cout << "Документ не был добавлен, так как его id совпадает с уже имеющимся"s << endl;
  444.     }
  445.     if (!search_server.AddDocument(-1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, {1, 2})) {
  446.         cout << "Документ не был добавлен, так как его id отрицательный"s << endl;
  447.     }
  448.     if (!search_server.AddDocument(3, "большой пёс скво\x12рец"s, DocumentStatus::ACTUAL, {1, 3, 2})) {
  449.         cout << "Документ не был добавлен, так как содержит спецсимволы"s << endl;
  450.     }
  451.     vector<Document> documents;
  452.     if (search_server.FindTopDocuments("--пушистый"s, documents)) {
  453.         for (const Document& document : documents) {
  454.             PrintDocument(document);
  455.         }
  456.     } else {
  457.         cout << "Ошибка в поисковом запросе"s << endl;
  458.     }
  459. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement