Advertisement
Alaricy

тест оптионал

Dec 14th, 2022
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.52 KB | None | 0 0
  1. #include <algorithm>
  2. #include <cmath>
  3. #include <iostream>
  4. #include <map>
  5. #include <set>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include <optional>
  10.  
  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. template <typename StringContainer>
  65. set<string> MakeUniqueNonEmptyStrings(const StringContainer& strings) {
  66.     set<string> non_empty_strings;
  67.     for (const string& str : strings) {
  68.         if (!str.empty()) {
  69.             non_empty_strings.insert(str);
  70.         }
  71.     }
  72.     return non_empty_strings;
  73. }
  74.  
  75. enum class DocumentStatus {
  76.     ACTUAL,
  77.     IRRELEVANT,
  78.     BANNED,
  79.     REMOVED,
  80. };
  81.  
  82.  
  83. class SearchServer {
  84. public:
  85.     inline static constexpr int INVALID_DOCUMENT_ID = -1;
  86.  
  87.  
  88.     template <typename StringContainer>
  89.     explicit SearchServer(const StringContainer& stop_words)
  90.         : stop_words_(MakeUniqueNonEmptyStrings(stop_words)) {
  91.     }
  92.  
  93.     explicit SearchServer(const string& stop_words_text)
  94.         : SearchServer(SplitIntoWords(stop_words_text))
  95.     {
  96.     }
  97.  
  98.     [[nodiscard]] bool AddDocument(int document_id, const string& document, DocumentStatus status, const vector<int>& ratings) {
  99.         if (document_id < 0 || documents_.count(document_id) > 0 ) {
  100.             return false;
  101.         }
  102.  
  103.         if (const auto words = SplitIntoWordsNoStop(document); words.has_value()) {
  104.             /*if (words->empty()) {
  105.                 return false;
  106.             }*/
  107.             for (const string& word : words.value()) {
  108.                 if (!IsValidWord(word)) {
  109.                     return false;
  110.                 }
  111.             }
  112.             /*if (words->empty()) {
  113.                 return false;
  114.             }*/
  115.             const double inv_word_count = 1.0 / words->size();
  116.             for (const string& word : words.value()) {
  117.                 word_to_document_freqs_[word][document_id] += inv_word_count;
  118.             }
  119.             documents_.emplace(document_id, DocumentData{ ComputeAverageRating(ratings), status });
  120.             documents_id.push_back(document_id);
  121.             return true;
  122.         }
  123.         else
  124.         {
  125.             return false;
  126.         }
  127.     }
  128.  
  129.     template <typename DocumentPredicate>
  130.     optional<vector<Document>> FindTopDocuments(const string& raw_query, DocumentPredicate document_predicate) const {
  131.  
  132.  
  133.         if (const auto query = ParseQuery(raw_query); query.has_value()) {
  134.             auto matched_documents = FindAllDocuments(query.value(), document_predicate);
  135.  
  136.             sort(matched_documents.begin(), matched_documents.end(),
  137.                 [](const Document& lhs, const Document& rhs) {
  138.                     if (abs(lhs.relevance - rhs.relevance) < 1e-6) {
  139.                         return lhs.rating > rhs.rating;
  140.                     }
  141.                     else {
  142.                         return lhs.relevance > rhs.relevance;
  143.                     }
  144.                 });
  145.             if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  146.                 matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  147.             }
  148.             return matched_documents;
  149.         }
  150.         else {
  151.             return nullopt;
  152.         }
  153.  
  154.     }
  155.  
  156.     optional<vector<Document>> FindTopDocuments(const string& raw_query, DocumentStatus status) const {
  157.         return FindTopDocuments(raw_query, [status](int document_id, DocumentStatus document_status, int rating) {
  158.             return document_status == status;
  159.             });
  160.     }
  161.  
  162.     optional<vector<Document>> FindTopDocuments(const string& raw_query) const {
  163.         return FindTopDocuments(raw_query, DocumentStatus::ACTUAL);
  164.     }
  165.  
  166.     int GetDocumentId(int index) const {
  167.         for (const auto& [key_id, value] : documents_) {
  168.             if (key_id == index) {
  169.                 return key_id;
  170.             }
  171.         }
  172.  
  173.         return INVALID_DOCUMENT_ID;
  174.     }
  175.  
  176.     int GetDocumentCount() const {
  177.         return static_cast<int>(documents_.size());
  178.     }
  179.  
  180.     optional<tuple<vector<string>, DocumentStatus>> MatchDocument(const string& raw_query, int document_id) const {
  181.          
  182.         if (const auto query = ParseQuery(raw_query); query.has_value()) {
  183.             vector<string> matched_words;
  184.             for (const string& word : query->plus_words) {
  185.                 if (word_to_document_freqs_.count(word) == 0) {
  186.                     continue;
  187.                 }
  188.                 if (word_to_document_freqs_.at(word).count(document_id)) {
  189.                     matched_words.push_back(word);
  190.                 }
  191.             }
  192.             for (const string& word : query->minus_words) {
  193.                 if (word_to_document_freqs_.count(word) == 0) {
  194.                     continue;
  195.                 }
  196.                 if (word_to_document_freqs_.at(word).count(document_id)) {
  197.                     matched_words.clear();
  198.                     break;
  199.                 }
  200.             }
  201.             tuple<vector<string>, DocumentStatus> returned_tuple = { matched_words, documents_.at(document_id).status };
  202.             return returned_tuple;
  203.         }
  204.         else {
  205.             return nullopt;
  206.         }
  207.        
  208.     }
  209.  
  210. private:
  211.     struct DocumentData {
  212.         int rating;
  213.         DocumentStatus status;
  214.     };
  215.     const set<string> stop_words_;
  216.     map<string, map<int, double>> word_to_document_freqs_;
  217.     map<int, DocumentData> documents_;
  218.     vector<int> documents_id;
  219.  
  220.     struct QueryWord {
  221.         string data;
  222.         bool is_minus;
  223.         bool is_stop;
  224.     };
  225.  
  226.     struct Query {
  227.         set<string> plus_words;
  228.         set<string> minus_words;
  229.     };
  230.  
  231.     bool IsStopWord(const string& word) const {
  232.         return stop_words_.count(word) > 0;
  233.     }
  234.  
  235.  
  236.     static bool IsValidWord(const string& word) {
  237.         return none_of(word.begin(), word.end(), [](char c) {
  238.             return c >= '\0' && c < ' ';
  239.             });
  240.     }
  241.  
  242.     optional<vector<string>> SplitIntoWordsNoStop(const string& text) const {
  243.         vector<string> words;
  244.         for (const string& word : SplitIntoWords(text)) {
  245.             if (!IsStopWord(word)) {
  246.                 if (word.empty() || !IsValidWord(word) || word == "-"s || word[0] == '-')
  247.                 {
  248.                     return nullopt;
  249.                 }
  250.                 words.push_back(word);
  251.             }
  252.         }
  253.  
  254.         return words;
  255.     }
  256.  
  257.     static int ComputeAverageRating(const vector<int>& ratings) {
  258.         if (ratings.empty()) {
  259.             return 0;
  260.         }
  261.         int rating_sum = 0;
  262.         for (const int rating : ratings) {
  263.             rating_sum += rating;
  264.         }
  265.         return rating_sum / static_cast<int>(ratings.size());
  266.     }
  267.  
  268.  
  269.  
  270.     QueryWord ParseQueryWord(string text) const {
  271.         bool is_minus = false;
  272.         // Word shouldn't be empty
  273.         if (text[0] == '-') {
  274.             is_minus = true;
  275.             text = text.substr(1);
  276.         }
  277.        
  278.         return { text, is_minus, IsStopWord(text) };
  279.     }
  280.  
  281.  
  282.  
  283.     optional<Query> ParseQuery(const string& text) const {
  284.         Query query;
  285.         for (const string& word : SplitIntoWords(text)) {
  286.             const QueryWord query_word = ParseQueryWord(word);
  287.             if (!query_word.is_stop) {
  288.                 if (query_word.is_minus) {
  289.                     if (query_word.data == "-"s || !IsValidWord(query_word.data) || query_word.data.empty() || query_word.data[0] == '-') {
  290.                         return nullopt;
  291.                     }
  292.                     query.minus_words.insert(query_word.data);
  293.                 }
  294.                 else {
  295.                     if (query_word.data == "-"s || !IsValidWord(query_word.data) || query_word.data.empty() || query_word.data[0] == '-') {
  296.                         return nullopt;
  297.                     }
  298.                     query.plus_words.insert(query_word.data);
  299.                 }
  300.             }
  301.         }
  302.  
  303.         /*for (const string& word : query.plus_words) {
  304.             if (word == "-"s || !IsValidWord(word) || word.empty() || word[0] == '-') {
  305.                 return nullopt;
  306.             }
  307.         }
  308.         for (const string& word : query.minus_words) {
  309.             if (word == "-"s || !IsValidWord(word) || word.empty() || word[0] == '-') {
  310.                 return nullopt;
  311.             }
  312.         }*/
  313.  
  314.         return query;
  315.     }
  316.  
  317.     double ComputeWordInverseDocumentFreq(const string& word) const {
  318.         return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  319.     }
  320.  
  321.     template <typename DocumentPredicate>
  322.     vector<Document> FindAllDocuments(const Query& query,
  323.         DocumentPredicate document_predicate) const {
  324.         map<int, double> document_to_relevance;
  325.         for (const string& word : query.plus_words) {
  326.             if (word_to_document_freqs_.count(word) == 0) {
  327.                 continue;
  328.             }
  329.             const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  330.             for (const auto [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  331.                 const auto& document_data = documents_.at(document_id);
  332.                 if (document_predicate(document_id, document_data.status, document_data.rating)) {
  333.                     document_to_relevance[document_id] += term_freq * inverse_document_freq;
  334.                 }
  335.             }
  336.         }
  337.  
  338.         for (const string& word : query.minus_words) {
  339.             if (word_to_document_freqs_.count(word) == 0) {
  340.                 continue;
  341.             }
  342.             for (const auto [document_id, _] : word_to_document_freqs_.at(word)) {
  343.                 document_to_relevance.erase(document_id);
  344.             }
  345.         }
  346.  
  347.         vector<Document> matched_documents;
  348.         for (const auto [document_id, relevance] : document_to_relevance) {
  349.             matched_documents.push_back(
  350.                 { document_id, relevance, documents_.at(document_id).rating });
  351.         }
  352.         return matched_documents;
  353.     }
  354. };
  355.  
  356. // ==================== для примера =========================
  357.  
  358. void PrintDocument(const Document& document) {
  359.     cout << "{ "s
  360.         << "document_id = "s << document.id << ", "s
  361.         << "relevance = "s << document.relevance << ", "s
  362.         << "rating = "s << document.rating << " }"s << endl;
  363. }
  364. int main() {
  365.     SearchServer search_server("и в на"s);
  366.     // Явно игнорируем результат метода AddDocument, чтобы избежать предупреждения
  367.     // о неиспользуемом результате его вызова
  368.     (void)search_server.AddDocument(1, "пушистый кот пушистый хвост"s, DocumentStatus::ACTUAL, { 7, 2, 7 });
  369.     if (!search_server.AddDocument(1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, { 1, 2 })) {
  370.         cout << "Документ не был добавлен, так как его id совпадает с уже имеющимся"s << endl;
  371.     }
  372.     if (!search_server.AddDocument(-1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, { 1, 2 })) {
  373.         cout << "Документ не был добавлен, так как его id отрицательный"s << endl;
  374.     }
  375.     if (!search_server.AddDocument(3, "большой пёс скво\x12рец"s, DocumentStatus::ACTUAL, { 1, 3, 2 })) {
  376.         cout << "Документ не был добавлен, так как содержит спецсимволы"s << endl;
  377.     }
  378.     if (const auto documents = search_server.FindTopDocuments("--пушистый"s)) {
  379.         for (const Document& document : *documents) {
  380.             PrintDocument(document);
  381.         }
  382.     }
  383.     else {
  384.         cout << "Ошибка в поисковом запросе"s << endl;
  385.     }
  386. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement