Advertisement
RobertDeMilo

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

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