delix777

Спринт 5. Выводим результаты поиска страницами.

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