Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <iostream>
- #include <set>
- #include <string>
- #include <utility>
- #include <vector>
- #include <map>
- #include <cmath>
- #include <numeric>
- #include <cassert>
- #include <tuple>
- #include <optional>
- using namespace std;
- const int MAX_RESULT_DOCUMENT_COUNT = 5;
- enum class DocumentStatus {
- ACTUAL,
- IRRELEVANT,
- BANNED,
- REMOVED
- };
- string ReadLine() {
- string s;
- getline(cin, s);
- return s;
- }
- int ReadLineWithNumber() {
- int result = 0;
- cin >> result;
- cin.ignore(50, '\n');
- return result;
- }
- vector<string> SplitIntoWords(const string& text) {
- vector<string> words;
- string word;
- for (const char c : text) {
- if (c == ' ') {
- if (!word.empty()) {
- words.push_back(word);
- word.clear();
- }
- }
- else {
- word += c;
- }
- }
- if (!word.empty()) {
- words.push_back(word);
- }
- return words;
- }
- vector<int> ReadLineWithRatings()
- {
- int num_of_ratings;
- cin >> num_of_ratings;
- int number = 0;
- vector<int> temp_result;
- for (int i = 0; i < num_of_ratings; ++i)
- {
- cin >> number;
- temp_result.push_back(number);
- }
- cin.ignore(2000, '\n');
- return temp_result;
- }
- struct Document //структура, являющаяся результатом наших вычислений/поисков по заданным критериям
- {
- Document()
- :id(0), relevance(0.f), rating(0)
- {
- }
- Document(int r_id, double r_relevance, int r_rating)
- :id(r_id), relevance(r_relevance), rating(r_rating)
- {
- }
- int id;
- double relevance;
- int rating;
- };
- //ОБЪЯВЛЕНИЕ КЛАССА SearchServer
- class SearchServer
- {
- public:
- inline static constexpr int INVALID_DOCUMENT_ID = -1;
- SearchServer()
- {
- }
- SearchServer(const string& raw_string)
- {
- for (const string& word : SplitIntoWords(raw_string))
- stop_words_.insert(word);
- }
- template <typename T>
- SearchServer(const T& raw_collection)
- {
- for (const string& word : raw_collection)
- stop_words_.insert(word);
- }
- int GetDocumentId(int index) const {
- return ((index >= 0) && (index < document_count_)) ? id_to_docnumber_.at(index) : SearchServer::INVALID_DOCUMENT_ID;
- }
- int GetDocumentCount() const
- {
- return document_count_;
- }
- //в первом элементе кортежа result метод возвращает все плюс-слова запроса, содержащиеся в документе
- optional<tuple<vector<string>, DocumentStatus>> MatchDocument(const string& raw_query, int document_id) const
- {
- if (document_id == SearchServer::INVALID_DOCUMENT_ID) //проверка на неверный индекс документа (и как следствие переданный неверный id)
- return nullopt;
- if (raw_query.empty()) //проверка на пустой запрос
- return nullopt;
- auto temp_query = ParseQuery(raw_query);
- if (!temp_query)
- return nullopt;
- vector<string> temp_string_res;
- if (temp_query->plus_words.empty() && !temp_query->minus_words.empty()) //проверка на ситуацию "в запросе только минус слова", это не ошибка, а возврат пустого результата
- return make_tuple(temp_string_res, docs_rat_n_stat_.at(document_id).doc_status);
- for (const auto& minus_word : temp_query->minus_words) //проверка на "если в запросе есть минус-слова то возвращаем пустой запрос" это не ошибка, а возврат пустого результата
- if (d_documents_.count(minus_word) != 0)
- if (d_documents_.at(minus_word).count(document_id))
- return make_tuple(temp_string_res, docs_rat_n_stat_.at(document_id).doc_status);
- for (const auto& plus_word : temp_query->plus_words)
- if (d_documents_.count(plus_word))
- if (d_documents_.at(plus_word).count(document_id))
- temp_string_res.push_back(plus_word);
- sort(temp_string_res.begin(), temp_string_res.end());
- return make_tuple(temp_string_res, docs_rat_n_stat_.at(document_id).doc_status);
- }
- void SetStopWords(const string& text)
- {
- for (const string& word : SplitIntoWords(text))
- stop_words_.insert(word);
- }
- [[nodiscard]] bool AddDocument(int document_id, const string& document, DocumentStatus status, const vector<int>& ratings)
- {
- if (document_id < 0 || docs_rat_n_stat_.count(document_id)) //проверка на отрицательный id и повторно введенный id
- return false;
- const vector<string> words = SplitIntoWordsNoStop(document);
- for (const auto& it : words)
- {
- if (IsValidWord(it)) //проверка на спецсимвол в запросе
- return false;
- if (d_documents_[it][document_id] > 0.0f) //если в словаре слово встречается в документе не первый раз
- {
- d_documents_[it][document_id] += 1.0f / words.size();
- }
- else //если слово встретили впервые, то создаем такую запись
- {
- d_documents_[it][document_id] = 1.0f / words.size();
- }
- }
- id_to_docnumber_[document_count_] = document_id;
- document_count_++;
- docs_rat_n_stat_.insert({ document_id, { ComputeAverageRating(ratings), status } });
- return true;
- }
- optional<vector<Document>> FindTopDocuments(const string& raw_query) const
- {
- //vector<Document> matched_documents;
- DocumentStatus status = DocumentStatus::ACTUAL;
- return this->FindTopDocuments(raw_query, [status](int document_id, DocumentStatus status_to_compare, int rating) { return status_to_compare == status;});
- }
- optional<vector<Document>> FindTopDocuments(const string& raw_query, DocumentStatus status) const
- {
- //vector<Document> matched_documents;
- return this->FindTopDocuments(raw_query, [status](int document_id, DocumentStatus status_to_compare, int rating) { return status_to_compare == status;});;
- }
- template <typename T>
- optional<vector<Document>> FindTopDocuments(const string& raw_query, T filter_function) const
- {
- if (raw_query.empty()) //проверка на пустой запрос
- return nullopt;
- auto temp_query = ParseQuery(raw_query);
- if (!temp_query)
- return nullopt;
- //Query query;
- //if (!ParseQuery(raw_query, query)) //проверка запроса на все дополнительные условия: отсутствие двойного "--", отсутствие текста после знака минус "- ", отсусттвие спецсимволов
- // return nullopt;
- auto result = FindAllDocuments(temp_query, filter_function);
- if (!result)
- return nullopt;
- const double EPSILON = 1e-6; //для расчета относительной погрешности и уточнении порядка сортировки
- sort(result->begin(), result->end(),
- [&EPSILON](const Document& lhs, const Document& rhs) {
- return (abs(lhs.relevance - rhs.relevance) < EPSILON) ? lhs.rating > rhs.rating:lhs.relevance > rhs.relevance;
- });
- //обрезаем количество выводимых документов в соответствии с заданным параметром MAX_RESULT_DOCUMENT_COUNT
- if (result->size() > MAX_RESULT_DOCUMENT_COUNT)
- result->resize(MAX_RESULT_DOCUMENT_COUNT);
- return result;
- }
- private:
- struct QueryWord
- {
- string data;
- bool is_minus;
- bool is_stop;
- };
- struct Query
- {
- set<string> plus_words;
- set<string> minus_words;
- };
- struct Docs_Rating_n_Status
- {
- int doc_rating;
- DocumentStatus doc_status;
- };
- map<int, Docs_Rating_n_Status> docs_rat_n_stat_; //контейнер для хранения id документа, структуры с рейтингом и статусом документа
- map<string, map<int, double>> d_documents_; //новый контейнер для хранения инвертированного индекса
- set<string> stop_words_;
- int document_count_ = 0; //новая переменная для хранения общего количества документов
- map<int, int> id_to_docnumber_; //контейнер для хранения соответствий id и порядкового номера документа
- bool IsStopWord(const string& word) const
- {
- return stop_words_.count(word) > 0;
- }
- vector<string> SplitIntoWordsNoStop(const string& text) const
- {
- vector<string> words;
- for (const string& word : SplitIntoWords(text)) {
- if (!IsStopWord(word)) {
- words.push_back(word);
- }
- }
- return words;
- }
- static bool IsValidWord(const string& word)
- {
- return count_if(word.begin(), word.end(), [](char ch) {return static_cast<int>(ch) >= 0 && static_cast<int>(ch) <= 31;});
- //алтернативный вариант через none_of
- /*return none_of(word.begin(), word.end(), [](char c) {
- return c >= '\0' && c < ' ';
- });*/
- }
- optional<QueryWord> ParseQueryWord(string text) const
- {
- bool is_minus = false;
- if (IsValidWord(text))
- return nullopt;
- if (text == "-"s)
- return nullopt;
- if (text[0] == '-')
- {
- if (text[1] == '-' || text[1] == ' ') // проверка на ошибки в поисковом запросе типа двойного "--" и отсутствие текста после знака - "- "
- return nullopt;
- is_minus = true;
- text = text.substr(1);
- }
- return QueryWord{ text, is_minus, IsStopWord(text) };
- }
- optional<Query> ParseQuery(const string& text) const
- {
- Query temp_query;
- if (SplitIntoWords(text).empty()) //проверка на пустой запрос
- return nullopt;
- for (const string& word : SplitIntoWords(text))
- {
- auto query_word = ParseQueryWord(word);
- if (!query_word) //проверка слова на "минусовость" и ошибки в поисковом запросе "--", "- ", наличие спецсимволов
- return nullopt;
- if (!query_word.value().is_stop)
- {
- if (query_word->is_minus)
- temp_query.minus_words.insert(query_word->data);
- else
- temp_query.plus_words.insert(query_word->data);
- }
- }
- return temp_query;
- }
- template <typename T>
- optional<vector<Document>> FindAllDocuments(const optional<Query>& query, T filter_function) const
- {
- map<int, double> relevance_table;
- for (auto& query_word : query->plus_words) //проходим по плюс словам
- {
- if (d_documents_.count(query_word)) //если в контейнере с обратным индексом есть плюс-слово
- {
- const double d = log(document_count_ / static_cast<double>(d_documents_.at(query_word).size())); //считаем IDF слова
- for (const auto& [id, TF] : d_documents_.at(query_word)) //проходим по ключу в контейнере индекса по всем документам в которых это слово есть
- {
- const auto& ref = docs_rat_n_stat_.at(id);
- if (filter_function(id, ref.doc_status, ref.doc_rating)) //если итерируемый id документа имеет условие, которое нам было передано в FindTopDocuments
- relevance_table[id] += d * TF; //считаем IDF-TF, заносим в таблицу релевантности
- //через распаковку будет выглядеть следующим образом:
- // const auto& [status, rating] = docs_rat_n_stat_.at(id);
- // if (filter_function(id, status, rating))
- }
- }
- }
- //проверка на минус-слова, исключение из matched_documents записей с номерами id, которые соответсвуют минус-словам в d_documents_
- for (const auto& minus_word : query->minus_words)
- if (d_documents_.count(minus_word) != 0)
- for (const auto& [id, TF] : d_documents_.at(minus_word))
- relevance_table.erase(id);
- vector<Document> result;
- for (const auto& [index, relevance] : relevance_table)
- result.push_back({ index,relevance,docs_rat_n_stat_.at(index).doc_rating });
- return result;
- }
- static int ComputeAverageRating(const vector<int>& ratings)
- {
- if (ratings.empty())
- return 0;
- int size_of_ratings = ratings.size();
- int sum_id_rating = accumulate(ratings.begin(), ratings.end(), 0);
- return sum_id_rating / size_of_ratings;
- }
- };
- //версии int main() и SearchServer CreateSearchServer() для тестирования результатов
- SearchServer CreateSearchServer() {
- SearchServer search_server("и в на"s);
- (void)search_server.AddDocument(1, "пушистый кот пушистый хвост"s, DocumentStatus::ACTUAL, { 7, 2, 7 });
- if (!search_server.AddDocument(1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, { 1, 2 })) {
- cout << "Документ не был добавлен, так как его id совпадает с уже имеющимся"s << endl;
- }
- if (!search_server.AddDocument(-1, "пушистый пёс и модный ошейник"s, DocumentStatus::ACTUAL, { 1, 2 })) {
- cout << "Документ не был добавлен, так как его id отрицательный"s << endl;
- }
- if (!search_server.AddDocument(3, "большой пёс скво\x12рец"s, DocumentStatus::ACTUAL, { 1, 3, 2 })) {
- cout << "Документ не был добавлен, так как содержит спецсимволы"s << endl;
- }
- return search_server;
- }
- void PrintDocument(const Document& docs_to_print)
- {
- cout << "{ document_id = "s << docs_to_print.id << ", "s
- << "relevance = "s << docs_to_print.relevance << ", "s
- << "rating = "s << docs_to_print.rating << " }"s << endl;
- }
- int main() {
- system("chcp 1251");
- const SearchServer search_server = CreateSearchServer();
- vector<Document> documents;
- if (search_server.FindTopDocuments("-кот"s, documents)) {
- for (const Document& document : documents) {
- PrintDocument(document);
- }
- }
- else {
- cout << "Ошибка в поисковом запросе"s << endl;
- }
- //tuple<vector<string>, DocumentStatus> test_tuple;
- if (const auto test_tuple = search_server.MatchDocument(" - "s, search_server.GetDocumentId(-2)))
- {
- //for(size_t it = 0; it < test_tuple.value(vector<string>); ++it)
- for (auto& it : test_tuple->_Myfirst._Val)
- {
- cout << it << " ";
- }
- }
- else
- {
- cout << "Ошибка в поисковом запросе типа TUPLE"s << endl;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment