Advertisement
khaze1

Untitled

Nov 17th, 2023
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.95 KB | None | 0 0
  1. #include <algorithm>
  2. #include <cmath>
  3. #include <iostream>
  4. #include <map>
  5. #include <numeric>
  6. #include <optional>
  7. #include <set>
  8. #include <string>
  9. #include <utility>
  10. #include <vector>
  11.  
  12.  
  13. using namespace std;
  14.  
  15. const int MAX_RESULT_DOCUMENT_COUNT = 5;
  16. const double EPSILON = 1e-6;
  17.  
  18. enum class DocumentStatus {
  19.     ACTUAL,
  20.     IRRELEVANT,
  21.     BANNED,
  22.     REMOVED
  23. };
  24.  
  25. struct Document {
  26.     Document() = default;
  27.     Document(int id, double relevance, int rating) : id(id), relevance(relevance), rating(rating){}
  28.     int id = 0;
  29.     double relevance = 0;
  30.     int rating = 0;
  31. };
  32.  
  33. ostream& operator<<(ostream& os, Document doc){
  34.     return os <<  "{ document id = " << doc.id
  35.             << ", relevance = " << doc.relevance
  36.             << ", rating = " << doc.rating << " }";
  37. }
  38.  
  39. string ReadLine() {
  40.     string s;
  41.     getline(cin, s);
  42.     return s;
  43. }
  44.  
  45. int ReadLineWithNumber() {
  46.     int result = 0;
  47.     cin >> result;
  48.     ReadLine();
  49.     return result;
  50. }
  51.  
  52.  
  53. vector<string> SplitIntoWords(const string& text) {
  54.     vector<string> words;
  55.     string word;
  56.     for (const char c : text) {
  57.         if (c == ' ') {
  58.             if (!word.empty()) {
  59.                 words.push_back(word);
  60.                 word.clear();
  61.             }
  62.         }
  63.         else if ('\0' <= c && c < ' '){
  64.             throw invalid_argument("special symbol"s);
  65.         }
  66.         else {
  67.             word += c;
  68.         }
  69.     }
  70.     if (!word.empty()) {
  71.         words.push_back(word);
  72.     }
  73.  
  74.     return words;
  75. }
  76.  
  77. template <typename StringContainer>
  78. set<string> MakeUniqueNonEmptyStrings(const StringContainer& strings) {
  79.     set<string> non_empty_strings;
  80.     for (const string& str : strings) {
  81.         if (!str.empty()) {
  82.             non_empty_strings.insert(str);
  83.         }
  84.     }
  85.     return non_empty_strings;
  86. }
  87.  
  88.  
  89. class SearchServer {
  90. public:
  91.     explicit SearchServer() = default;
  92.  
  93.     template <typename T>
  94.     explicit SearchServer(const T& stop_words)
  95.             : stop_words_(MakeUniqueNonEmptyStrings(stop_words)) {
  96.         for (const string& stop_word : stop_words_){
  97.             if (!IsValidWord(stop_word)) throw invalid_argument("special symbol"s);
  98.         }
  99.     }
  100.  
  101.     explicit SearchServer(const string& stop_words_str) : SearchServer(SplitIntoWords(stop_words_str)) {}
  102.  
  103.     static bool IsValidWord(const string& word) {
  104.         return none_of(word.begin(), word.end(), [](char c) {
  105.             return c >= '\0' && c < ' ';
  106.         });
  107.     }
  108.  
  109.  
  110.     int GetDocumentId(int ordinal_num) const {
  111.         if (ordinal_num < 0 || ordinal_num >= static_cast<int>(order_.size()))
  112.             throw out_of_range("invalid id"s);
  113.  
  114.         return order_.at(ordinal_num);
  115.     }
  116.    
  117.  
  118.     bool IsDocumentExist(int id) const {
  119.         return documents_.count(id);
  120.     }
  121.  
  122.  
  123.     int GetDocumentCount() const {
  124.         return document_count_;
  125.     };
  126.  
  127.     tuple<vector<string>, DocumentStatus> MatchDocument(const string& raw_query, int id) const{
  128.  
  129.         auto& map_ = word_to_document_freqs_;
  130.        
  131.         if ( !IsDocumentExist(id) ){
  132.             throw invalid_argument("invalid id"s);
  133.         }
  134.  
  135.         const auto query = ParseQuery(SplitIntoWordsNoStop(raw_query));
  136.         tuple<vector<string>, DocumentStatus> result;
  137.         get<1>(result) = documents_.at(id).status;
  138.        
  139.         for (const string& word : query.minus_words){
  140.             auto ptr = map_.find(word);
  141.             if (ptr == map_.end()) continue;
  142.             if (ptr->second.count(id)) return result;
  143.         }
  144.         for (const string& word : query.plus_words){
  145.             auto ptr = map_.find(word);
  146.             if (ptr == map_.end()) continue;
  147.             if (ptr->second.count(id))
  148.                 get<0>(result).push_back(word);
  149.         }
  150.        
  151.         return result;
  152.     }
  153.    
  154.     void AddDocument(int id, const string& document_text
  155.     , DocumentStatus status, const vector<int>& ratings){
  156.  
  157.         if (id < 0)
  158.             throw invalid_argument("id is less then zero"s);
  159.  
  160.         if (IsDocumentExist(id))
  161.             throw invalid_argument("a document with this id already exists"s);
  162.  
  163.         vector<string> words = SplitIntoWordsNoStop(document_text);
  164.         order_.push_back(id);
  165.         int rating = ComputeAverageRating(ratings);
  166.         double tf = 1. / words.size();
  167.         for (const string& word : words){
  168.             word_to_document_freqs_[word][id] += tf;
  169.         }
  170.         documents_[id] = {rating, status};
  171.         ++document_count_;
  172.     }
  173.    
  174.     template <typename Predicate>
  175.     vector<Document> FindTopDocuments(const string& raw_query
  176.             , Predicate predicate) const {
  177.                
  178.         const auto query = ParseQuery(SplitIntoWordsNoStop(raw_query));
  179.         vector<Document> matched_documents = FindAllDocuments(query, predicate);
  180.        
  181.         sort(matched_documents.begin(), matched_documents.end(),
  182.                 [](const Document& ld, const Document& rd) {
  183.                     return (ld.relevance > rd.relevance
  184.                     || (std::abs(ld.relevance - rd.relevance)  < EPSILON
  185.                         && ld.rating > rd.rating));
  186.                 }
  187.             );
  188.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  189.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  190.         }
  191.    
  192.         return matched_documents;
  193.     }
  194.  
  195.     vector<Document> FindTopDocuments(const string& raw_query
  196.             , DocumentStatus status_ = DocumentStatus::ACTUAL) const {
  197.         return FindTopDocuments(raw_query, [status_](int id, DocumentStatus status, int rating){
  198.                 return status == status_;
  199.         });
  200.     }
  201.  
  202. private:
  203.     struct Query{
  204.         set<string> plus_words;
  205.         set<string> minus_words;
  206.     };
  207.     struct DocumentData{
  208.         int rating;
  209.         DocumentStatus status;
  210.     };
  211.  
  212.     int document_count_ = 0;
  213.     set<string> stop_words_;
  214.     map<string, map<int, double>> word_to_document_freqs_;
  215.     map<int, DocumentData> documents_;
  216.     vector<int> order_;
  217.  
  218.      vector<string> SplitIntoWordsNoStop(const string& text) const {
  219.         vector<string> words;
  220.         for (const string& word : SplitIntoWords(text)) {
  221.             if (stop_words_.count(word) == 0) {
  222.                 words.push_back(word);
  223.             }
  224.         }
  225.         return words;
  226.     }
  227.  
  228.     Query ParseQuery(const vector<string>& words) const {
  229.         Query query;
  230.         for (const string& word : words) {
  231.             if (word[0] == '-') {
  232.                 if (word.size() == 1u) throw invalid_argument("the '-' stands alone"s);
  233.                 if (word[1] == '-') throw invalid_argument("double '-'"s);
  234.                 query.minus_words.insert(string(word.begin() + 1, word.end()));
  235.             }
  236.             else {
  237.                 query.plus_words.insert(word);
  238.             }
  239.         }
  240.         return query;
  241.     }
  242.  
  243.     double ComputeIDF(const string& word) const {
  244.         return log( static_cast<double>(document_count_)
  245.             / static_cast<double>(word_to_document_freqs_.at(word).size()) );
  246.     }
  247.  
  248.     static int ComputeAverageRating(const vector<int>& ratings) {
  249.         if (ratings.size() == 0) return 0;
  250.         return accumulate(ratings.begin(), ratings.end(), 0) / static_cast<int>(ratings.size());
  251.     }
  252.  
  253.     void ExcludeMinusWords(const Query& query, map<int, double>& docs_relevance) const {
  254.         for (const string& word : query.minus_words){
  255.             if (word_to_document_freqs_.count(word)){
  256.                 for (const auto& [id, tf] : word_to_document_freqs_.at(word)){
  257.                     docs_relevance.erase(id);
  258.                 }
  259.             }
  260.         }
  261.     }
  262.  
  263.     template <typename Predicate>
  264.     vector<Document> FindAllDocuments(const Query& query, Predicate predicate) const {
  265.         map<int, double> docs_relevance;
  266.         vector<Document> matched_documents;
  267.         for (const string& word : query.plus_words){
  268.             if (word_to_document_freqs_.count(word)){
  269.                 const double idf = ComputeIDF(word);
  270.                 for (const auto& [id, tf] : word_to_document_freqs_.at(word)){
  271.                     docs_relevance[id] += idf * tf;
  272.                 }
  273.                 }
  274.         }
  275.         ExcludeMinusWords(query, docs_relevance);
  276.         for (const auto& [id, relevance] : docs_relevance){
  277.             if (predicate(id, documents_.at(id).status, documents_.at(id).rating)){
  278.                 matched_documents.push_back({id, relevance, documents_.at(id).rating});
  279.             }
  280.             }
  281.             return matched_documents;
  282.     }
  283.  
  284. };
  285.  
  286. template <typename It>
  287. class IterRange{
  288. public:
  289.     IterRange(It begin, It end) : begin_(begin), end_(end), size_(distance(begin, end)) {}
  290.  
  291.     It begin() {
  292.         return begin_;
  293.     }
  294.     It end() {
  295.         return end_;
  296.     }
  297.     size_t size() {
  298.         return size_;
  299.     }
  300.  
  301. private:
  302.     It begin_;
  303.     It end_;
  304.     size_t size_;
  305. };
  306.  
  307. template <typename it>
  308. void PrintRange(it first, it end){
  309.  
  310.     while (first != end){
  311.         std::cout << *first;
  312.         ++first;
  313.     }
  314.  
  315. }
  316.  
  317. template <typename It>
  318. ostream& operator<<(ostream& os, IterRange<It> Ir){
  319.  
  320.     for (auto it = Ir.begin(); it != Ir.end(); ++it){
  321.         os << *it;
  322.     }
  323.  
  324.     return os;
  325. }
  326.  
  327. template<typename It>
  328. class Paginator{
  329. public:
  330.     Paginator(It begin, It end, size_t page_size){
  331.         It page_begin = begin;
  332.         It page_end = begin;
  333.    
  334.         while (page_end != end){
  335.             page_begin = page_end;
  336.             if (static_cast<int>(page_size) <= distance(page_begin, end)){
  337.                 advance(page_end, page_size);
  338.             }else{
  339.                 page_end = end;
  340.             }  
  341.             pages_.push_back(IterRange(page_begin, page_end));
  342.         }
  343.     }
  344.  
  345.     auto begin() const {
  346.         return pages_.begin();
  347.     }
  348.  
  349.     auto end() const {
  350.         return pages_.end();
  351.     }
  352.  
  353. private:
  354.  
  355.     vector<IterRange<It>> pages_;
  356.  
  357. };
  358.  
  359. template <typename Container>
  360. auto Paginate(const Container& c, size_t page_size){
  361.     return Paginator(c.begin(), c.end(), page_size);
  362. }
  363.  
  364.  
  365. int main(){
  366.    
  367.     SearchServer search_server("and with"s);
  368.     search_server.AddDocument(1, "funny pet and nasty rat"s, DocumentStatus::ACTUAL, {7, 2, 7});
  369.     search_server.AddDocument(2, "funny pet with curly hair"s, DocumentStatus::ACTUAL, {1, 2, 3});
  370.     search_server.AddDocument(3, "big cat nasty hair"s, DocumentStatus::ACTUAL, {1, 2, 8});
  371.     search_server.AddDocument(4, "big dog cat Vladislav"s, DocumentStatus::ACTUAL, {1, 3, 2});
  372.     search_server.AddDocument(5, "big dog hamster Borya"s, DocumentStatus::ACTUAL, {1, 1, 1});
  373.  
  374.     const auto search_results = search_server.FindTopDocuments("curly dog"s);
  375.     int page_size = 2;
  376.     const auto pages = Paginate(search_results, page_size);
  377.     // Выводим найденные документы по страницам
  378.     for (auto page = pages.begin(); page != pages.end(); ++page) {
  379.         cout << *page << endl;
  380.         cout << "Page break"s << endl;
  381.     }
  382.    
  383. }
  384.  
  385.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement