Punchcard

IteratorRange

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