Advertisement
oster_man

Paginator

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