Advertisement
kutuzzzov

Урок 2

Sep 27th, 2022 (edited)
659
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.37 KB | None | 0 0
  1. #include <algorithm>
  2. #include <iostream>
  3. #include <set>
  4. #include <string>
  5. #include <utility>
  6. #include <vector>
  7. #include <map>
  8. #include <cmath>
  9. #include <cassert>
  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 = 0;
  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.         }
  38.         else {
  39.             word += c;
  40.         }
  41.     }
  42.     if (!word.empty()) {
  43.         words.push_back(word);
  44.     }
  45.     return words;
  46. }
  47.  
  48. struct Document {
  49.     Document() = default;
  50.  
  51.     Document(int id_, double relevance_, int rating_)
  52.         : id(id_), relevance(relevance_), rating(rating_)
  53.     {}
  54.  
  55.     int id = 0;
  56.     double relevance = 0.0;
  57.     int rating = 0;
  58. };
  59.  
  60. enum class DocumentStatus {
  61.     ACTUAL,
  62.     IRRELEVANT,
  63.     BANNED,
  64.     REMOVED
  65. };
  66.  
  67. class SearchServer {
  68. public:
  69.     // Defines an invalid document id
  70.     // You can refer to this constant as SearchServer::INVALID_DOCUMENT_ID
  71.     inline static constexpr int INVALID_DOCUMENT_ID = -1;
  72.  
  73.     SearchServer() = default;
  74.  
  75.     explicit SearchServer(const string& stop_words) {
  76.         for (const string& word : SplitIntoWords(stop_words)) {
  77.             stop_words_.insert(word);
  78.         }
  79.     }
  80.  
  81.     template <typename StringCollection>
  82.     explicit SearchServer(const StringCollection& stop_words) {
  83.         string stop_words_text;
  84.         for (const auto& text : stop_words) {
  85.             stop_words_text += " "s;
  86.             stop_words_text += text;
  87.         }
  88.         for (const auto& word : SplitIntoWords(stop_words_text)) {
  89.             stop_words_.insert(word);
  90.         }
  91.     }
  92.  
  93.     [[nodiscard]] bool AddDocument(int document_id, const string& document, DocumentStatus status, const vector<int>& ratings) {
  94.         if (document_id < 0) {
  95.             return false;
  96.         }
  97.         if (documents_.find(document_id) != documents_.end()) {
  98.             return false;
  99.         }
  100.  
  101.         const vector<string> words = SplitIntoWordsNoStop(document);
  102.         for (auto& word : words) {
  103.             if (!IsValidWord(word)) {
  104.                 return false;
  105.             }
  106.         }
  107.         for (auto& word : words) {
  108.             word_to_document_freqs_[word][document_id] += 1.0 / words.size();
  109.         }
  110.         documents_.emplace(document_id, DocumentData { ComputeAverageRating(ratings), status });
  111.         documents_index_.push_back(document_id);
  112.  
  113.         return true;
  114.     }
  115.  
  116.     int GetDocumentCount() const {
  117.         return static_cast<int>(documents_.size());
  118.     }
  119.  
  120.     template <typename DocumentPredicate>
  121.     [[nodiscard]] bool FindTopDocuments(const string& raw_query, DocumentPredicate document_predicate, vector<Document>& result) const {
  122.         if (raw_query.empty()) {
  123.             return false;
  124.         }
  125.  
  126.         for (const string& word : SplitIntoWords(raw_query)) {
  127.             if (!IsValidWord(word)) {
  128.                 return false;
  129.             }
  130.             if (!IsValidMinusWord(word)) {
  131.                 return false;
  132.             }
  133.         }
  134.  
  135.         const Query query = ParseQuery(raw_query);
  136.         auto matched_documents = FindAllDocuments(query, document_predicate);
  137.  
  138.         sort(matched_documents.begin(), matched_documents.end(),
  139.             [](const Document& lhs, const Document& rhs) {
  140.                 const double EPSILON = 1e-6;
  141.                 if (abs(lhs.relevance - rhs.relevance) < EPSILON) {
  142.                     return lhs.rating > rhs.rating;
  143.                 }
  144.                 else {
  145.                     return lhs.relevance > rhs.relevance;
  146.                 }
  147.             });
  148.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  149.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  150.         }
  151.  
  152.         result = matched_documents;
  153.         return true;
  154.     }
  155.  
  156.     [[nodiscard]] bool FindTopDocuments(const string& raw_query, DocumentStatus status, vector<Document>& result) const {
  157.         return FindTopDocuments(raw_query,
  158.             [&status](int document_id, DocumentStatus new_status, int rating) {
  159.                 return new_status == status;
  160.             }, result);
  161.     }
  162.  
  163.     [[nodiscard]] bool FindTopDocuments(const string& raw_query, vector<Document>& result) const {
  164.         return FindTopDocuments(raw_query, DocumentStatus::ACTUAL, result);
  165.     }
  166.  
  167.     [[nodiscard]] bool MatchDocument(const string& raw_query, int document_id, tuple<vector<string>, DocumentStatus>& result) const {
  168.         if (raw_query.empty()) {
  169.             return false;
  170.         }
  171.  
  172.         for (const string& word : SplitIntoWords(raw_query)) {
  173.             if (!IsValidWord(word)) {
  174.                 return false;
  175.             }
  176.             if (!IsValidMinusWord(word)) {
  177.                 return false;
  178.             }
  179.         }
  180.  
  181.         const Query query = ParseQuery(raw_query);
  182.         vector<string> matched_words;
  183.         for (const string& word : query.plus_words) {
  184.             if (word_to_document_freqs_.count(word) == 0) {
  185.                 continue;
  186.             }
  187.             if (word_to_document_freqs_.at(word).count(document_id)) {
  188.                 matched_words.push_back(word);
  189.             }
  190.         }
  191.         for (const string& word : query.minus_words) {
  192.             if (word_to_document_freqs_.count(word) == 0) {
  193.                 continue;
  194.             }
  195.             if (word_to_document_freqs_.at(word).count(document_id)) {
  196.                 matched_words.clear();
  197.                 break;
  198.             }
  199.         }
  200.  
  201.         result = { matched_words, documents_.at(document_id).status };
  202.         return true;
  203.     }
  204.  
  205.     int GetDocumentId(int index) const {
  206.         if ((index >= 0) && (index < static_cast<int>(documents_.size()))) {
  207.             return documents_index_[index];
  208.         }
  209.         return SearchServer::INVALID_DOCUMENT_ID;
  210.     }
  211.  
  212. private:
  213.     struct Query {
  214.         set<string> plus_words;
  215.         set<string> minus_words;
  216.     };
  217.  
  218.     struct DocumentData {
  219.         int rating;
  220.         DocumentStatus status;
  221.     };
  222.  
  223.     map<string, map<int, double>> word_to_document_freqs_;
  224.     map<int, DocumentData> documents_;
  225.     set<string> stop_words_;
  226.     vector<int> documents_index_;
  227.  
  228.     bool IsStopWord(const string& word) const {
  229.         return stop_words_.count(word) > 0;
  230.     }
  231.  
  232.     static bool IsValidWord(const string& word) {
  233.         // A valid word must not contain special characters
  234.         return none_of(word.begin(), word.end(), [](char c) {
  235.             return c >= '\0' && c < ' ';
  236.             });
  237.     }
  238.  
  239.     static bool IsValidMinusWord(const string& word) {
  240.         if (word.empty()) {
  241.             return false;
  242.         }
  243.         if (word == "-"s) {
  244.             return false;
  245.         }
  246.         if (word[0] == '-' && word[1] == '-') {
  247.             return false;
  248.         }
  249.  
  250.         return true;
  251.     }
  252.  
  253.     vector<string> SplitIntoWordsNoStop(const string& text) const {
  254.         vector<string> words;
  255.         for (const string& word : SplitIntoWords(text)) {
  256.             if (!IsStopWord(word)) {
  257.                 words.push_back(word);
  258.             }
  259.         }
  260.         return words;
  261.     }
  262.  
  263.     static int ComputeAverageRating(const vector<int>& ratings) {
  264.         if (ratings.empty()) {
  265.             return 0;
  266.         }
  267.         int rating_sum = 0;
  268.         for (const auto rating : ratings) {
  269.             rating_sum += rating;
  270.         }
  271.         return rating_sum / static_cast<int>(ratings.size());
  272.     }
  273.  
  274.     Query ParseQuery(const string& text) const {
  275.         Query query;
  276.         for (string& word : SplitIntoWordsNoStop(text)) {
  277.             if (word[0] == '-') {
  278.                 word = word.substr(1);
  279.                 if (!IsStopWord(word)) {
  280.                     query.minus_words.insert(word);
  281.                 }
  282.             }
  283.             query.plus_words.insert(word);
  284.         }
  285.         return query;
  286.     }
  287.  
  288.     template<typename DocumentPredicate>
  289.     vector<Document> FindAllDocuments(const Query& query, DocumentPredicate predicate) const {
  290.         map<int, double> document_to_relevance;
  291.         for (const string& word : query.plus_words) {
  292.             if (word_to_document_freqs_.count(word) == 0) {
  293.                 continue;
  294.             }
  295.             for (const auto& [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  296.                 const DocumentData documents_data = documents_.at(document_id);
  297.                 if (predicate(document_id, documents_data.status, documents_data.rating)) {
  298.                     const double IDF = log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  299.                     document_to_relevance[document_id] += IDF * term_freq;
  300.                 }
  301.             }
  302.         }
  303.         for (const string& word : query.minus_words) {
  304.             if (word_to_document_freqs_.count(word) == 0) {
  305.                 continue;
  306.             }
  307.             for (const auto& [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  308.                 document_to_relevance.erase(document_id);
  309.             }
  310.         }
  311.  
  312.         vector<Document> matched_documents;
  313.         for (const auto [document_id, relevance] : document_to_relevance) {
  314.             matched_documents.push_back({ document_id, relevance, documents_.at(document_id).rating });
  315.         }
  316.         return matched_documents;
  317.     }
  318. };
  319.  
  320. void PrintDocument(const Document& document) {
  321.     cout << "{ "s
  322.         << "document_id = "s << document.id << ", "s
  323.         << "relevance = "s << document.relevance << ", "s
  324.         << "rating = "s << document.rating
  325.         << " }"s << endl;
  326. }
  327.  
  328. int main() {
  329.     setlocale(LC_ALL, "Russian");
  330.  
  331.     SearchServer search_server("и в на"s);
  332.  
  333.     // Явно игнорируем результат метода AddDocument, чтобы избежать предупреждения
  334.     // о неиспользуемом результате его вызова
  335.     (void)search_server.AddDocument(1, "пушистый кот пушистый хвост"s, DocumentStatus::ACTUAL, { 7, 2, 7 });
  336.  
  337.     if (!search_server.AddDocument(1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, { 1, 2 })) {
  338.         cout << "Документ не был добавлен, так как его id совпадает с уже имеющимся"s << endl;
  339.     }
  340.  
  341.     if (!search_server.AddDocument(-1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, { 1, 2 })) {
  342.         cout << "Документ не был добавлен, так как его id отрицательный"s << endl;
  343.     }
  344.  
  345.     if (!search_server.AddDocument(3, "большой пёс скво\x12рец"s, DocumentStatus::ACTUAL, { 1, 3, 2 })) {
  346.         cout << "Документ не был добавлен, так как содержит спецсимволы"s << endl;
  347.     }
  348.  
  349.     vector<Document> documents;
  350.     if (search_server.FindTopDocuments("--пушистый"s, documents)) {
  351.         for (const Document& document : documents) {
  352.             PrintDocument(document);
  353.         }
  354.     }
  355.     else {
  356.         cout << "Ошибка в поисковом запросе"s << endl;
  357.     }
  358. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement