shizaero

Untitled

May 8th, 2023
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.42 KB | None | 0 0
  1. #include <algorithm>
  2. #include <cmath>
  3. #include <iostream>
  4. #include <map>
  5. #include <set>
  6. #include <stdexcept>
  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. //Содержит итератор начала, итератор конца и вспомогательные методы
  16. template <typename Iterator>
  17. class IteratorRange {
  18.     IteratorRange(Iterator it_begin, Iterator it_end) :
  19.         it_begin_(it_begin), it_end_(it_end) {}
  20.  
  21.     Iterator begin() {
  22.         return it_begin_;
  23.     }
  24.     Iterator end() {
  25.         return it_end_;
  26.     }
  27.     int size() {
  28.         return distance(it_begin_, it_end_);
  29.     }
  30. private:
  31.     Iterator it_begin_;
  32.     Iterator it_end_;
  33. };
  34.  
  35. template <typename Iterator>
  36. class Paginator {
  37.     Paginator(Iterator it_cont_begin, Iterator it_cont_end, size_t page_size) {
  38.         for (auto it = it_cont_begin; it < it_cont_end; ++it) {
  39.             IteratorRange page(it, advance(it, page_size));
  40.             content_.push_back(page);
  41.         }
  42.     }
  43. private:
  44.     vector<IteratorRange<Iterator>> content_;
  45. };
  46.  
  47. template <typename Container>
  48. auto Paginate(const Container& c, size_t page_size) {
  49.     return Paginator(begin(c), end(c), page_size);
  50. }
  51.  
  52. string ReadLine() {
  53.     string s;
  54.     getline(cin, s);
  55.     return s;
  56. }
  57.  
  58. int ReadLineWithNumber() {
  59.     int result;
  60.     cin >> result;
  61.     ReadLine();
  62.     return result;
  63. }
  64.  
  65. vector<string> SplitIntoWords(const string& text) {
  66.     vector<string> words;
  67.     string word;
  68.     for (const char c : text) {
  69.         if (c == ' ') {
  70.             if (!word.empty()) {
  71.                 words.push_back(word);
  72.                 word.clear();
  73.             }
  74.         } else {
  75.             word += c;
  76.         }
  77.     }
  78.     if (!word.empty()) {
  79.         words.push_back(word);
  80.     }
  81.  
  82.     return words;
  83. }
  84.  
  85. struct Document {
  86.     Document() = default;
  87.  
  88.     Document(int id, double relevance, int rating)
  89.         : id(id)
  90.         , relevance(relevance)
  91.         , rating(rating) {
  92.     }
  93.  
  94.     int id = 0;
  95.     double relevance = 0.0;
  96.     int rating = 0;
  97. };
  98.  
  99. template <typename StringContainer>
  100. set<string> MakeUniqueNonEmptyStrings(const StringContainer& strings) {
  101.     set<string> non_empty_strings;
  102.     for (const string& str : strings) {
  103.         if (!str.empty()) {
  104.             non_empty_strings.insert(str);
  105.         }
  106.     }
  107.     return non_empty_strings;
  108. }
  109.  
  110. enum class DocumentStatus {
  111.     ACTUAL,
  112.     IRRELEVANT,
  113.     BANNED,
  114.     REMOVED,
  115. };
  116.  
  117. class SearchServer {
  118. public:
  119.     template <typename StringContainer>
  120.     explicit SearchServer(const StringContainer& stop_words)
  121.         : stop_words_(MakeUniqueNonEmptyStrings(stop_words))  // Extract non-empty stop words
  122.     {
  123.         if (!all_of(stop_words_.begin(), stop_words_.end(), IsValidWord)) {
  124.             throw invalid_argument("Some of stop words are invalid"s);
  125.         }
  126.     }
  127.  
  128.     explicit SearchServer(const string& stop_words_text)
  129.         : SearchServer(
  130.             SplitIntoWords(stop_words_text))  // Invoke delegating constructor from string container
  131.     {
  132.     }
  133.  
  134.     void AddDocument(int document_id, const string& document, DocumentStatus status,
  135.                      const vector<int>& ratings) {
  136.         if ((document_id < 0) || (documents_.count(document_id) > 0)) {
  137.             throw invalid_argument("Invalid document_id"s);
  138.         }
  139.         const auto words = SplitIntoWordsNoStop(document);
  140.  
  141.         const double inv_word_count = 1.0 / words.size();
  142.         for (const string& word : words) {
  143.             word_to_document_freqs_[word][document_id] += inv_word_count;
  144.         }
  145.         documents_.emplace(document_id, DocumentData{ComputeAverageRating(ratings), status});
  146.         document_ids_.push_back(document_id);
  147.     }
  148.  
  149.     template <typename DocumentPredicate>
  150.     vector<Document> FindTopDocuments(const string& raw_query,
  151.                                       DocumentPredicate document_predicate) const {
  152.         const auto query = ParseQuery(raw_query);
  153.  
  154.         auto matched_documents = FindAllDocuments(query, document_predicate);
  155.  
  156.         sort(matched_documents.begin(), matched_documents.end(),
  157.              [](const Document& lhs, const Document& rhs) {
  158.                  if (abs(lhs.relevance - rhs.relevance) < 1e-6) {
  159.                      return lhs.rating > rhs.rating;
  160.                  } else {
  161.                      return lhs.relevance > rhs.relevance;
  162.                  }
  163.              });
  164.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  165.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  166.         }
  167.  
  168.         return matched_documents;
  169.     }
  170.  
  171.     vector<Document> FindTopDocuments(const string& raw_query, DocumentStatus status) const {
  172.         return FindTopDocuments(
  173.             raw_query, [status](int document_id, DocumentStatus document_status, int rating) {
  174.                 return document_status == status;
  175.             });
  176.     }
  177.  
  178.     vector<Document> FindTopDocuments(const string& raw_query) const {
  179.         return FindTopDocuments(raw_query, DocumentStatus::ACTUAL);
  180.     }
  181.  
  182.     int GetDocumentCount() const {
  183.         return documents_.size();
  184.     }
  185.  
  186.     int GetDocumentId(int index) const {
  187.         return document_ids_.at(index);
  188.     }
  189.  
  190.     tuple<vector<string>, DocumentStatus> MatchDocument(const string& raw_query,
  191.                                                         int document_id) const {
  192.         const auto query = ParseQuery(raw_query);
  193.  
  194.         vector<string> matched_words;
  195.         for (const string& word : query.plus_words) {
  196.             if (word_to_document_freqs_.count(word) == 0) {
  197.                 continue;
  198.             }
  199.             if (word_to_document_freqs_.at(word).count(document_id)) {
  200.                 matched_words.push_back(word);
  201.             }
  202.         }
  203.         for (const string& word : query.minus_words) {
  204.             if (word_to_document_freqs_.count(word) == 0) {
  205.                 continue;
  206.             }
  207.             if (word_to_document_freqs_.at(word).count(document_id)) {
  208.                 matched_words.clear();
  209.                 break;
  210.             }
  211.         }
  212.         return {matched_words, documents_.at(document_id).status};
  213.     }
  214.  
  215. private:
  216.     struct DocumentData {
  217.         int rating;
  218.         DocumentStatus status;
  219.     };
  220.     const set<string> stop_words_;
  221.     map<string, map<int, double>> word_to_document_freqs_;
  222.     map<int, DocumentData> documents_;
  223.     vector<int> document_ids_;
  224.  
  225.     bool IsStopWord(const string& word) const {
  226.         return stop_words_.count(word) > 0;
  227.     }
  228.  
  229.     static bool IsValidWord(const string& word) {
  230.         // A valid word must not contain special characters
  231.         return none_of(word.begin(), word.end(), [](char c) {
  232.             return c >= '\0' && c < ' ';
  233.         });
  234.     }
  235.  
  236.     vector<string> SplitIntoWordsNoStop(const string& text) const {
  237.         vector<string> words;
  238.         for (const string& word : SplitIntoWords(text)) {
  239.             if (!IsValidWord(word)) {
  240.                 throw invalid_argument("Word "s + word + " is invalid"s);
  241.             }
  242.             if (!IsStopWord(word)) {
  243.                 words.push_back(word);
  244.             }
  245.         }
  246.         return words;
  247.     }
  248.  
  249.     static int ComputeAverageRating(const vector<int>& ratings) {
  250.         if (ratings.empty()) {
  251.             return 0;
  252.         }
  253.         int rating_sum = 0;
  254.         for (const int rating : ratings) {
  255.             rating_sum += rating;
  256.         }
  257.         return rating_sum / static_cast<int>(ratings.size());
  258.     }
  259.  
  260.     struct QueryWord {
  261.         string data;
  262.         bool is_minus;
  263.         bool is_stop;
  264.     };
  265.  
  266.     QueryWord ParseQueryWord(const string& text) const {
  267.         if (text.empty()) {
  268.             throw invalid_argument("Query word is empty"s);
  269.         }
  270.         string word = text;
  271.         bool is_minus = false;
  272.         if (word[0] == '-') {
  273.             is_minus = true;
  274.             word = word.substr(1);
  275.         }
  276.         if (word.empty() || word[0] == '-' || !IsValidWord(word)) {
  277.             throw invalid_argument("Query word "s + text + " is invalid");
  278.         }
  279.  
  280.         return {word, is_minus, IsStopWord(word)};
  281.     }
  282.  
  283.     struct Query {
  284.         set<string> plus_words;
  285.         set<string> minus_words;
  286.     };
  287.  
  288.     Query ParseQuery(const string& text) const {
  289.         Query result;
  290.         for (const string& word : SplitIntoWords(text)) {
  291.             const auto query_word = ParseQueryWord(word);
  292.             if (!query_word.is_stop) {
  293.                 if (query_word.is_minus) {
  294.                     result.minus_words.insert(query_word.data);
  295.                 } else {
  296.                     result.plus_words.insert(query_word.data);
  297.                 }
  298.             }
  299.         }
  300.         return result;
  301.     }
  302.  
  303.     // Existence required
  304.     double ComputeWordInverseDocumentFreq(const string& word) const {
  305.         return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  306.     }
  307.  
  308.     template <typename DocumentPredicate>
  309.     vector<Document> FindAllDocuments(const Query& query,
  310.                                       DocumentPredicate document_predicate) const {
  311.         map<int, double> document_to_relevance;
  312.         for (const string& word : query.plus_words) {
  313.             if (word_to_document_freqs_.count(word) == 0) {
  314.                 continue;
  315.             }
  316.             const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  317.             for (const auto [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  318.                 const auto& document_data = documents_.at(document_id);
  319.                 if (document_predicate(document_id, document_data.status, document_data.rating)) {
  320.                     document_to_relevance[document_id] += term_freq * inverse_document_freq;
  321.                 }
  322.             }
  323.         }
  324.  
  325.         for (const string& word : query.minus_words) {
  326.             if (word_to_document_freqs_.count(word) == 0) {
  327.                 continue;
  328.             }
  329.             for (const auto [document_id, _] : word_to_document_freqs_.at(word)) {
  330.                 document_to_relevance.erase(document_id);
  331.             }
  332.         }
  333.  
  334.         vector<Document> matched_documents;
  335.         for (const auto [document_id, relevance] : document_to_relevance) {
  336.             matched_documents.push_back(
  337.                 {document_id, relevance, documents_.at(document_id).rating});
  338.         }
  339.         return matched_documents;
  340.     }
  341. };
  342.  
  343. int main() {
  344.     SearchServer search_server("and with"s);
  345.     search_server.AddDocument(1, "funny pet and nasty rat"s, DocumentStatus::ACTUAL, { 7, 2, 7 });
  346.     search_server.AddDocument(2, "funny pet with curly hair"s, DocumentStatus::ACTUAL, { 1, 2, 3 });
  347.     search_server.AddDocument(3, "big cat nasty hair"s, DocumentStatus::ACTUAL, { 1, 2, 8 });
  348.     search_server.AddDocument(4, "big dog cat Vladislav"s, DocumentStatus::ACTUAL, { 1, 3, 2 });
  349.     search_server.AddDocument(5, "big dog hamster Borya"s, DocumentStatus::ACTUAL, { 1, 1, 1 });
  350.     const auto search_results = search_server.FindTopDocuments("curly dog"s);
  351.     int page_size = 2;
  352.     const auto pages = Paginate(search_results, page_size);
  353.     // Выводим найденные документы по страницам
  354.     for (auto page = pages.begin(); page != pages.end(); ++page) {
  355.         cout << *page << endl;
  356.         cout << "Page break"s << endl;
  357.     }
  358. }
Advertisement
Add Comment
Please, Sign In to add comment