Advertisement
chevengur

ИТОГОВЫЙ ПРОЕКТ 4 СПРИНТА

Dec 23rd, 2023
612
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.49 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 <numeric>
  10.  
  11. using namespace std;
  12.  
  13. const int MAX_RESULT_DOCUMENT_COUNT = 5;
  14. const double VALUE = 1e-6;
  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) : id(id), relevance(relevance), rating(rating) {
  54.  
  55.     }
  56.  
  57.     int id = 0;
  58.     double relevance = 0.0;
  59.     int rating = 0;
  60. };
  61.  
  62. template <typename StringContainer>
  63. set<string> MakeUniqueNonEmptyStrings(const StringContainer& strings) {
  64.     set<string> non_empty_strings;
  65.     for (const string& str : strings) {
  66.         if (!str.empty()) {
  67.             non_empty_strings.insert(str);
  68.         }
  69.     }
  70.     return non_empty_strings;
  71. }
  72.  
  73. enum class DocumentStatus {
  74.     ACTUAL,
  75.     IRRELEVANT,
  76.     BANNED,
  77.     REMOVED,
  78. };
  79.  
  80. class SearchServer {
  81. public:
  82.     template <typename StringContainer>
  83.     explicit SearchServer(StringContainer stop_words)
  84.         : stop_words_(MakeUniqueNonEmptyStrings(stop_words))
  85.     {
  86.         for (string word : stop_words)
  87.         {
  88.             if (!IsValidWord(word)) {
  89.                 stop_words.clear();
  90.                 throw invalid_argument("Error: invalid_argument(SearchServerConstruct1)");
  91.             }
  92.         }
  93.     }
  94.  
  95.     explicit SearchServer(const string& stop_words_text)
  96.         : SearchServer(SplitIntoWords(stop_words_text)) {  // Invoke delegating constructor from string container
  97.  
  98.     }
  99.  
  100.     // Defines an invalid document id
  101.     // You can refer to this constant as SearchServer::INVALID_DOCUMENT_ID
  102.     inline static constexpr int INVALID_DOCUMENT_ID = -1;
  103.     void AddDocument(int document_id, const string& document, DocumentStatus status, const vector<int>& ratings) {
  104.  
  105.         auto doc_count = documents_.count(document_id);
  106.         if (doc_count) {
  107.             throw invalid_argument("invalid_argument(AddDocument_doc_have_this_document)");
  108.         }
  109.         if (document_id < 0) {
  110.             throw invalid_argument("invalid_argument(AddDocument_doc<-1)");
  111.         }
  112.         if (!IsValidWord(document)) {
  113.             throw invalid_argument("invalid_argument(AddDocument_doc_have_problem_withc_text)");
  114.         }
  115.         const vector<string> words = SplitIntoWordsNoStop(document);
  116.         const double inv_word_count = 1.0 / words.size();
  117.         for (const string& word : words)
  118.         {
  119.             word_to_document_freqs_[word][document_id] += inv_word_count;
  120.         }
  121.         documents_.emplace(document_id, DocumentData{ ComputeAverageRating(ratings), status });
  122.         index_document_.push_back(document_id);
  123.     }
  124.  
  125.  
  126.     template <typename DocumentPredicate>
  127.     vector<Document> FindTopDocuments(const string& raw_query, DocumentPredicate document_predicate) const {
  128.  
  129.         const Query query = ParseQuery(raw_query);
  130.         auto matched_documents = FindAllDocuments(query, document_predicate);
  131.  
  132.         sort(matched_documents.begin(), matched_documents.end(),
  133.             [](const Document& lhs, const Document& rhs) {
  134.                 if (abs(lhs.relevance - rhs.relevance) < VALUE) {
  135.                     return lhs.rating > rhs.rating;
  136.                 }
  137.         return lhs.relevance > rhs.relevance;
  138.  
  139.             });
  140.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  141.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  142.         }
  143.         return matched_documents;
  144.     }
  145.  
  146.     vector<Document> FindTopDocuments(const string& raw_query, DocumentStatus status) const {
  147.         return FindTopDocuments(raw_query, [status](int document_id, DocumentStatus document_status, int rating) {
  148.             return document_status == status;
  149.             });
  150.     }
  151.  
  152.     vector<Document> FindTopDocuments(const string& raw_query) const {
  153.         return FindTopDocuments(raw_query, DocumentStatus::ACTUAL);
  154.     }
  155.  
  156.     int GetDocumentCount() const {
  157.         return documents_.size();
  158.     }
  159.  
  160.     tuple<vector<string>, DocumentStatus> MatchDocument(const string& raw_query, int document_id) const {
  161.  
  162.         const Query query = ParseQuery(raw_query);
  163.         vector<string> matched_words;
  164.         for (const string& word : query.plus_words) {
  165.             if (word_to_document_freqs_.count(word) == 0) {
  166.                 continue;
  167.             }
  168.             if (word_to_document_freqs_.at(word).count(document_id)) {
  169.                 matched_words.push_back(word);
  170.             }
  171.         }
  172.         for (const string& word : query.minus_words) {
  173.             if (word_to_document_freqs_.count(word) == 0) {
  174.                 continue;
  175.             }
  176.             if (word_to_document_freqs_.at(word).count(document_id)) {
  177.                 matched_words.clear();
  178.                 break;
  179.             }
  180.         }
  181.         return tuple{ matched_words, documents_.at(document_id).status };
  182.     }
  183.  
  184.     int GetDocumentId(int index) const {
  185.         if (index > GetDocumentCount() || index <= INVALID_DOCUMENT_ID)
  186.             throw out_of_range(" out_of_range(GetDocumentID");
  187.         else
  188.             return index_document_[index];
  189.     }
  190.  
  191. private:
  192.  
  193.     struct DocumentData {
  194.         int rating;
  195.         DocumentStatus status;
  196.     };
  197.  
  198.     vector<int> index_document_;
  199.     const set<string> stop_words_;
  200.     map<string, map<int, double>> word_to_document_freqs_;
  201.     map<int, DocumentData> documents_;
  202.  
  203.  
  204.     bool IsStopWord(const string& word) const {
  205.         return stop_words_.count(word) > 0;
  206.     }
  207.  
  208.     //проверка на спецсимволы
  209.     static bool IsValidWord(const string& word)
  210.     {
  211.         // A valid word must not contain special characters
  212.         return none_of(word.begin(), word.end(), [](char c) {
  213.             return c >= '\0' && c < ' ';
  214.             });
  215.     }
  216.     vector<string> SplitIntoWordsNoStop(const string& text) const {
  217.         vector<string> words;
  218.         for (const string& word : SplitIntoWords(text)) {
  219.             if (!IsStopWord(word)) {
  220.                 words.push_back(word);
  221.             }
  222.         }
  223.         return words;
  224.     }
  225.  
  226.     static int ComputeAverageRating(const vector<int>& ratings) {
  227.         if (ratings.empty()) {
  228.             return 0;
  229.         }
  230.  
  231.         int rating_sum = accumulate(ratings.begin(), ratings.end(), 0);
  232.         return rating_sum / static_cast<int>(ratings.size());
  233.     }
  234.  
  235.     struct QueryWord {
  236.         string data;
  237.         bool is_minus;
  238.         bool is_stop;
  239.     };
  240.  
  241.     QueryWord ParseQueryWord(string text) const {
  242.         bool is_minus = false;
  243.         // Word shouldn't be empty
  244.         if (!IsValidWord(text)) {
  245.             throw invalid_argument(" invalid_argument(Don't valid word)");
  246.         }
  247.  
  248.         if (text[0] == '-') {
  249.             is_minus = true;
  250.             text = text.substr(1);
  251.         }
  252.          
  253.         if (text.empty() || text[0] == '-') {
  254.             throw invalid_argument(" invalid_argument(Last symbol = '-')");
  255.         }
  256.          
  257.         return { text, is_minus, IsStopWord(text) };
  258.     }
  259.  
  260.     struct Query {
  261.         set<string> plus_words;
  262.         set<string> minus_words;
  263.     };
  264.  
  265.     Query ParseQuery(const string& text) const {
  266.         Query query;
  267.         for (const string& word : SplitIntoWords(text)) {
  268.             const QueryWord query_word = ParseQueryWord(word);
  269.             if (!query_word.is_stop) {
  270.                 if (query_word.is_minus) {
  271.                     query.minus_words.insert(query_word.data);
  272.                 }
  273.                 else {
  274.                     query.plus_words.insert(query_word.data);
  275.                 }
  276.             }
  277.         }
  278.         return query;
  279.     }
  280.  
  281.     // Existence required
  282.     double ComputeWordInverseDocumentFreq(const string& word) const {
  283.         return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  284.     }
  285.  
  286.     template <typename DocumentPredicate>
  287.     vector<Document> FindAllDocuments(const Query& query,
  288.         DocumentPredicate document_predicate) const {
  289.         map<int, double> document_to_relevance;
  290.         for (const string& word : query.plus_words) {
  291.             if (word_to_document_freqs_.count(word) == 0) {
  292.                 continue;
  293.             }
  294.             const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  295.             for (const auto [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  296.                 const auto& document_data = documents_.at(document_id);
  297.                 if (document_predicate(document_id, document_data.status, document_data.rating)) {
  298.                     document_to_relevance[document_id] += term_freq * inverse_document_freq;
  299.                 }
  300.             }
  301.         }
  302.  
  303.         for (const string& word : query.minus_words) {
  304.             if (word_to_document_freqs_.count(word) == 0) {
  305.                 continue;
  306.             }
  307.             for (const auto [document_id, _] : word_to_document_freqs_.at(word)) {
  308.                 document_to_relevance.erase(document_id);
  309.             }
  310.         }
  311.  
  312.         vector<Document> matched_documents;
  313.         for (const auto [document_id, relevance] : document_to_relevance) {
  314.             matched_documents.push_back(
  315.                 { document_id, relevance, documents_.at(document_id).rating });
  316.         }
  317.         return matched_documents;
  318.     }
  319. };
  320.  
  321. // ==================== для примера =========================
  322.  
  323. void PrintDocument(const Document& document) {
  324.     cout << "{ "s
  325.         << "document_id = "s << document.id << ", "s
  326.         << "relevance = "s << document.relevance << ", "s
  327.         << "rating = "s << document.rating << " }"s << endl;
  328. }
  329. int main() {
  330.  
  331.     //setlocale(LC_ALL, "RU");
  332.  
  333.     try
  334.     {
  335.         SearchServer search_server("и в на"s);
  336.         (void)search_server.AddDocument(1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, { 1, 2 });
  337.         (void)search_server.AddDocument(2, "ewaeae awea"s, DocumentStatus::ACTUAL, { 1, 2 });
  338.         (void)search_server.AddDocument(3, "изумительныйplayboy"s, DocumentStatus::ACTUAL, { 1, 3, 2 });
  339.         (void)search_server.AddDocument(4, "большой пёс скворец"s, DocumentStatus::ACTUAL, { 1, 3, 2, 4 });
  340.         (void)search_server.AddDocument(5, "пушистый кот пушистый хвостcc"s, DocumentStatus::ACTUAL, { 7, 2, 7 });
  341.  
  342.         vector<Document> documents = search_server.FindTopDocuments("пушистый кот --"s);
  343.         for (const Document& document : documents) {
  344.             PrintDocument(document);
  345.         }
  346.     }
  347.  
  348.     catch (const invalid_argument& e) {
  349.         cout << "Error: "s << e.what() << endl;
  350.     }
  351. }
  352.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement