Advertisement
RobertDeMilo

Очередь запросов

Nov 16th, 2023
37
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.15 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. #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.         }
  39.         else {
  40.             word += c;
  41.         }
  42.     }
  43.     if (!word.empty()) {
  44.         words.push_back(word);
  45.     }
  46.  
  47.     return words;
  48. }
  49.  
  50. struct Document {
  51.     Document() = default;
  52.  
  53.     Document(int id, double relevance, int rating)
  54.         : id(id)
  55.         , relevance(relevance)
  56.         , rating(rating) {
  57.     }
  58.  
  59.     int id = 0;
  60.     double relevance = 0.0;
  61.     int rating = 0;
  62. };
  63.  
  64. ostream& operator<< (ostream& out, const Document& document)
  65. {
  66.     out << "{ document_id = "s << document.id << ", relevance = "s << document.relevance
  67.         << ", rating = " << document.rating << " }"s;
  68.  
  69.     return out;
  70. }
  71.  
  72.  
  73. template <typename StringContainer>
  74. set<string> MakeUniqueNonEmptyStrings(const StringContainer& strings) {
  75.     set<string> non_empty_strings;
  76.     for (const string& str : strings) {
  77.         if (!str.empty()) {
  78.             non_empty_strings.insert(str);
  79.         }
  80.     }
  81.     return non_empty_strings;
  82. }
  83.  
  84. enum class DocumentStatus {
  85.     ACTUAL,
  86.     IRRELEVANT,
  87.     BANNED,
  88.     REMOVED,
  89. };
  90.  
  91. template<typename Iterator>
  92. class IteratorRange
  93. {
  94. public:
  95.  
  96.     IteratorRange(Iterator begin, Iterator end, size_t size)
  97.     {
  98.         begin_ = begin;
  99.         end_ = end;
  100.         size_ = size;
  101.     }
  102.     Iterator begin() const
  103.     {
  104.         return begin_;
  105.     }
  106.     Iterator end() const
  107.     {
  108.         return end_;
  109.     }
  110.  
  111. private:
  112.  
  113.     Iterator begin_;
  114.     Iterator end_;
  115.     size_t size_;
  116. };
  117.  
  118.  
  119. template<typename Iterator>
  120. ostream& operator<<(ostream& out, const  IteratorRange <Iterator>& ir)
  121. {
  122.     for (auto it = ir.begin(); it != ir.end(); ++it)
  123.     {
  124.         out << *it;
  125.     }
  126.     return out;
  127. }
  128.  
  129. template<typename Iterator>
  130. IteratorRange<Iterator>& operator*(IteratorRange<Iterator> ir)
  131. {
  132.     return ir;
  133. }
  134.  
  135. template <typename Iterator>
  136. class Paginator
  137. {
  138. public:
  139.     Paginator(Iterator range_begin, Iterator range_end, size_t sizz)
  140.     {
  141.         /*int max_size = range_end - range_begin;*/
  142.         int max_size = distance(range_begin, range_end);
  143.         int size = sizz;
  144.  
  145.         for (auto it = range_begin; it != range_end;)
  146.         {
  147.             int add = min(max_size, size);
  148.  
  149.             auto first = it;
  150.             /*auto second = it + add;*/
  151.             auto second = it;
  152.             advance(second, add);
  153.  
  154.             ir_.push_back({ first , second, sizz });
  155.  
  156.             /*it += add;*/
  157.             advance(it, add);
  158.  
  159.             max_size -= size;
  160.         }
  161.     }
  162.     auto begin() const
  163.     {
  164.         return ir_.begin();
  165.     }
  166.     auto end() const
  167.     {
  168.         return ir_.end();
  169.     }
  170.  
  171. private:
  172.     vector<IteratorRange<Iterator>> ir_;
  173. };
  174.  
  175.  
  176. class SearchServer {
  177. public:
  178.     template <typename StringContainer>
  179.     explicit SearchServer(const StringContainer& stop_words)
  180.         : stop_words_(MakeUniqueNonEmptyStrings(stop_words))  // Extract non-empty stop words
  181.     {
  182.         if (!all_of(stop_words_.begin(), stop_words_.end(), IsValidWord)) {
  183.             throw invalid_argument("Some of stop words are invalid"s);
  184.         }
  185.     }
  186.  
  187.     explicit SearchServer(const string& stop_words_text)
  188.         : SearchServer(
  189.             SplitIntoWords(stop_words_text))  // Invoke delegating constructor from string container
  190.     {
  191.     }
  192.  
  193.     void AddDocument(int document_id, const string& document, DocumentStatus status,
  194.         const vector<int>& ratings) {
  195.         if ((document_id < 0) || (documents_.count(document_id) > 0)) {
  196.             throw invalid_argument("Invalid document_id"s);
  197.         }
  198.         const auto words = SplitIntoWordsNoStop(document);
  199.  
  200.         const double inv_word_count = 1.0 / words.size();
  201.         for (const string& word : words) {
  202.             word_to_document_freqs_[word][document_id] += inv_word_count;
  203.         }
  204.         documents_.emplace(document_id, DocumentData{ ComputeAverageRating(ratings), status });
  205.         document_ids_.push_back(document_id);
  206.     }
  207.  
  208.     template <typename DocumentPredicate>
  209.     vector<Document> FindTopDocuments(const string& raw_query,
  210.         DocumentPredicate document_predicate) const {
  211.         const auto query = ParseQuery(raw_query);
  212.  
  213.         auto matched_documents = FindAllDocuments(query, document_predicate);
  214.  
  215.         sort(matched_documents.begin(), matched_documents.end(),
  216.             [](const Document& lhs, const Document& rhs) {
  217.                 if (abs(lhs.relevance - rhs.relevance) < 1e-6) {
  218.                     return lhs.rating > rhs.rating;
  219.                 }
  220.                 else {
  221.                     return lhs.relevance > rhs.relevance;
  222.                 }
  223.             });
  224.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  225.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  226.         }
  227.  
  228.         return matched_documents;
  229.     }
  230.  
  231.     vector<Document> FindTopDocuments(const string& raw_query, DocumentStatus status) const {
  232.         return FindTopDocuments(
  233.             raw_query, [status](int document_id, DocumentStatus document_status, int rating) {
  234.                 return document_status == status;
  235.             });
  236.     }
  237.  
  238.     vector<Document> FindTopDocuments(const string& raw_query) const {
  239.         return FindTopDocuments(raw_query, DocumentStatus::ACTUAL);
  240.     }
  241.  
  242.     int GetDocumentCount() const {
  243.         return documents_.size();
  244.     }
  245.  
  246.     int GetDocumentId(int index) const {
  247.         return document_ids_.at(index);
  248.     }
  249.  
  250.     tuple<vector<string>, DocumentStatus> MatchDocument(const string& raw_query,
  251.         int document_id) const {
  252.         const auto query = ParseQuery(raw_query);
  253.  
  254.         vector<string> matched_words;
  255.         for (const string& word : query.plus_words) {
  256.             if (word_to_document_freqs_.count(word) == 0) {
  257.                 continue;
  258.             }
  259.             if (word_to_document_freqs_.at(word).count(document_id)) {
  260.                 matched_words.push_back(word);
  261.             }
  262.         }
  263.         for (const string& word : query.minus_words) {
  264.             if (word_to_document_freqs_.count(word) == 0) {
  265.                 continue;
  266.             }
  267.             if (word_to_document_freqs_.at(word).count(document_id)) {
  268.                 matched_words.clear();
  269.                 break;
  270.             }
  271.         }
  272.         return { matched_words, documents_.at(document_id).status };
  273.     }
  274.  
  275. private:
  276.     struct DocumentData {
  277.         int rating;
  278.         DocumentStatus status;
  279.     };
  280.     const set<string> stop_words_;
  281.     map<string, map<int, double>> word_to_document_freqs_;
  282.     map<int, DocumentData> documents_;
  283.     vector<int> document_ids_;
  284.  
  285.     bool IsStopWord(const string& word) const {
  286.         return stop_words_.count(word) > 0;
  287.     }
  288.  
  289.     static bool IsValidWord(const string& word) {
  290.         // A valid word must not contain special characters
  291.         return none_of(word.begin(), word.end(), [](char c) {
  292.             return c >= '\0' && c < ' ';
  293.             });
  294.     }
  295.  
  296.     vector<string> SplitIntoWordsNoStop(const string& text) const {
  297.         vector<string> words;
  298.         for (const string& word : SplitIntoWords(text)) {
  299.             if (!IsValidWord(word)) {
  300.                 throw invalid_argument("Word "s + word + " is invalid"s);
  301.             }
  302.             if (!IsStopWord(word)) {
  303.                 words.push_back(word);
  304.             }
  305.         }
  306.         return words;
  307.     }
  308.  
  309.     static int ComputeAverageRating(const vector<int>& ratings) {
  310.         if (ratings.empty()) {
  311.             return 0;
  312.         }
  313.         int rating_sum = 0;
  314.         for (const int rating : ratings) {
  315.             rating_sum += rating;
  316.         }
  317.         return rating_sum / static_cast<int>(ratings.size());
  318.     }
  319.  
  320.     struct QueryWord {
  321.         string data;
  322.         bool is_minus;
  323.         bool is_stop;
  324.     };
  325.  
  326.     QueryWord ParseQueryWord(const string& text) const {
  327.         if (text.empty()) {
  328.             throw invalid_argument("Query word is empty"s);
  329.         }
  330.         string word = text;
  331.         bool is_minus = false;
  332.         if (word[0] == '-') {
  333.             is_minus = true;
  334.             word = word.substr(1);
  335.         }
  336.         if (word.empty() || word[0] == '-' || !IsValidWord(word)) {
  337.             throw invalid_argument("Query word "s + text + " is invalid");
  338.         }
  339.  
  340.         return { word, is_minus, IsStopWord(word) };
  341.     }
  342.  
  343.     struct Query {
  344.         set<string> plus_words;
  345.         set<string> minus_words;
  346.     };
  347.  
  348.     Query ParseQuery(const string& text) const {
  349.         Query result;
  350.         for (const string& word : SplitIntoWords(text)) {
  351.             const auto query_word = ParseQueryWord(word);
  352.             if (!query_word.is_stop) {
  353.                 if (query_word.is_minus) {
  354.                     result.minus_words.insert(query_word.data);
  355.                 }
  356.                 else {
  357.                     result.plus_words.insert(query_word.data);
  358.                 }
  359.             }
  360.         }
  361.         return result;
  362.     }
  363.  
  364.     // Existence required
  365.     double ComputeWordInverseDocumentFreq(const string& word) const {
  366.         return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  367.     }
  368.  
  369.     template <typename DocumentPredicate>
  370.     vector<Document> FindAllDocuments(const Query& query,
  371.         DocumentPredicate document_predicate) const {
  372.         map<int, double> document_to_relevance;
  373.         for (const string& word : query.plus_words) {
  374.             if (word_to_document_freqs_.count(word) == 0) {
  375.                 continue;
  376.             }
  377.             const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  378.             for (const auto [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  379.                 const auto& document_data = documents_.at(document_id);
  380.                 if (document_predicate(document_id, document_data.status, document_data.rating)) {
  381.                     document_to_relevance[document_id] += term_freq * inverse_document_freq;
  382.                 }
  383.             }
  384.         }
  385.  
  386.         for (const string& word : query.minus_words) {
  387.             if (word_to_document_freqs_.count(word) == 0) {
  388.                 continue;
  389.             }
  390.             for (const auto [document_id, _] : word_to_document_freqs_.at(word)) {
  391.                 document_to_relevance.erase(document_id);
  392.             }
  393.         }
  394.  
  395.         vector<Document> matched_documents;
  396.         for (const auto [document_id, relevance] : document_to_relevance) {
  397.             matched_documents.push_back(
  398.                 { document_id, relevance, documents_.at(document_id).rating });
  399.         }
  400.         return matched_documents;
  401.     }
  402. };
  403. /////////////////////////////////////////////////////////////////////////////////////////
  404. class RequestQueue {
  405. public:
  406.     explicit RequestQueue(const SearchServer& search_server) :sr_(search_server)
  407.     {
  408.        
  409.     }
  410.  
  411.     // сделаем "обёртки" для всех методов поиска, чтобы сохранять результаты для нашей статистики
  412.     template <typename DocumentPredicate>
  413.     vector<Document> AddFindRequest(const string& raw_query, DocumentPredicate document_predicate) {
  414.        
  415.         vector<Document> docs = sr_.FindTopDocuments(raw_query, document_predicate);
  416.         Adjust(requests_);
  417.  
  418.         QueryResult qr;
  419.  
  420.         if (docs.empty())
  421.         {
  422.             qr.time_point += 1;
  423.             qr.is_empty_request = true;
  424.         }
  425.         else
  426.         {
  427.             qr.time_point += 1;
  428.             qr.is_empty_request = false;
  429.         }
  430.  
  431.         requests_.push_back(qr);
  432.         return docs;
  433.     }
  434.     vector<Document> AddFindRequest(const string& raw_query, DocumentStatus status) {
  435.        
  436.         vector<Document> docs = sr_.FindTopDocuments(raw_query, status);
  437.         Adjust(requests_);
  438.  
  439.         QueryResult qr;
  440.  
  441.         if (docs.empty())
  442.         {
  443.             qr.time_point += 1;
  444.             qr.is_empty_request = true;
  445.         }
  446.         else
  447.         {
  448.             qr.time_point += 1;
  449.             qr.is_empty_request = false;
  450.         }
  451.         requests_.push_back(qr);
  452.  
  453.         return docs;
  454.     }
  455.  
  456.     vector<Document> AddFindRequest(const string& raw_query) {
  457.  
  458.         vector<Document> docs = sr_.FindTopDocuments(raw_query);
  459.         Adjust(requests_);
  460.  
  461.         QueryResult qr;
  462.  
  463.         if (docs.empty())
  464.         {
  465.             qr.time_point += 1;
  466.             qr.is_empty_request = true;
  467.         }
  468.         else
  469.         {
  470.             qr.time_point += 1;
  471.             qr.is_empty_request = false;
  472.         }
  473.  
  474.         requests_.push_back(qr);
  475.         return docs;
  476.  
  477.     }
  478.     int GetNoResultRequests() const {
  479.         return count_if(requests_.begin(), requests_.end(), [](const QueryResult& qr)
  480.             { return qr.is_empty_request == true; });
  481.  
  482.     }
  483. private:
  484.     struct QueryResult
  485.     {
  486.         bool is_empty_request;
  487.         static int time_point;
  488.  
  489.     };
  490.  
  491.     deque<QueryResult> requests_;
  492.  
  493.     const static int min_in_day_ = 1440;
  494.  
  495.     const SearchServer& sr_;
  496.  
  497.     void Adjust(deque<QueryResult>& requests_)
  498.     {
  499.         if (!requests_.empty() && requests_.back().time_point >= min_in_day_)
  500.         {
  501.             requests_.pop_front();
  502.         }
  503.     }
  504.  
  505. };
  506. int RequestQueue::QueryResult::time_point = 0;
  507. /////////////////////////////////////////////////////////////////////////////////////////
  508.  
  509. template <typename Container>
  510. auto Paginate(const Container& c, size_t page_size) {
  511.     return Paginator(begin(c), end(c), page_size);
  512. }
  513.  
  514. int main() {
  515.     SearchServer search_server("and in at"s);
  516.  
  517.     RequestQueue request_queue(search_server);
  518.  
  519.     search_server.AddDocument(1, "curly cat curly tail"s, DocumentStatus::ACTUAL, { 7, 2, 7 });
  520.     search_server.AddDocument(2, "curly dog and fancy collar"s, DocumentStatus::ACTUAL, { 1, 2, 3 });
  521.     search_server.AddDocument(3, "big cat fancy collar "s, DocumentStatus::ACTUAL, { 1, 2, 8 });
  522.     search_server.AddDocument(4, "big dog sparrow Eugene"s, DocumentStatus::ACTUAL, { 1, 3, 2 });
  523.     search_server.AddDocument(5, "big dog sparrow Vasiliy"s, DocumentStatus::ACTUAL, { 1, 1, 1 });
  524.  
  525.     // 1439 запросов с нулевым результатом
  526.     for (int i = 0; i < 1439; ++i)
  527.     {
  528.         request_queue.AddFindRequest("empty request"s);
  529.     }
  530.  
  531.     // все еще 1439 запросов с нулевым результатом
  532.     request_queue.AddFindRequest("curly dog"s);
  533.  
  534.     // новые сутки, первый запрос удален, 1438 запросов с нулевым результатом
  535.     request_queue.AddFindRequest("big collar"s);
  536.  
  537.     // первый запрос удален, 1437 запросов с нулевым результатом
  538.     request_queue.AddFindRequest("sparrow"s);
  539.  
  540.     cout << "Total empty requests: "s << request_queue.GetNoResultRequests() << endl;
  541.     return 0;
  542. }
  543. // Total empty requests: 1437
  544.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement