delix777

Спринт 5. Очередь запросов.

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