shizaero

Untitled

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