Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <cmath>
- #include <iostream>
- #include <map>
- #include <numeric>
- #include <set>
- #include <string>
- #include <utility>
- #include <vector>
- using namespace std;
- const int MAX_RESULT_DOCUMENT_COUNT = 5;
- string ReadLine() {
- string s;
- getline(cin, s);
- return s;
- }
- int ReadLineWithNumber() {
- int result;
- cin >> result;
- ReadLine();
- 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;
- }
- struct Document {
- Document()= default;
- Document(int id, double rel, int rat):
- id(id), relevance(rel), rating(rat)
- {}
- int id = 0;
- double relevance = 0;
- int rating = 0;
- };
- enum class DocumentStatus {
- ACTUAL,
- IRRELEVANT,
- BANNED,
- REMOVED,
- };
- class SearchServer {
- public:
- // Defines an invalid document id
- // You can refer to this constant as SearchServer::INVALID_DOCUMENT_ID
- inline static constexpr int INVALID_DOCUMENT_ID = -1;
- SearchServer(){
- stop_words_.insert("");
- }
- template <typename StringCollection>
- explicit SearchServer(const StringCollection& stop_words) {
- for (const auto& element: stop_words){
- stop_words_.emplace(element);
- }
- }
- explicit SearchServer(const string& stop_words_text):SearchServer(SplitIntoWords(stop_words_text)){}
- 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 || documents_.count(document_id) > 0) {
- return false;
- }
- const vector<string> words = SplitIntoWordsNoStop(document);
- const double inv_word_count = 1.0 / words.size();
- for (const string& word : words) {
- if (!IsValidWord(word)) {
- return false;
- }
- word_to_document_freqs_[word][document_id] += inv_word_count;
- }
- documents_.emplace(document_id, DocumentData{ComputeAverageRating(ratings), status});
- document_index_.push_back(document_id);
- ++document_count_;
- return true;
- }
- // [[nodiscard]] bool FindTopDocuments(const string& raw_query, DocumentStatus doc_status = DocumentStatus::ACTUAL, vector<Document>& result) const{
- // if (FindTopDocuments(
- // raw_query, [doc_status](int document_id, DocumentStatus document_status, int rating) {
- // return document_status == doc_status;
- // }, result)) {
- // return true;
- // }
- // // return false;
- // // return FindTopDocuments(raw_query, [doc_status](int document_id, DocumentStatus status, int rating, vector<Document>& result) { return status == doc_status; });
- // }
- // vector<Document> FindTopDocuments(const string& raw_query) const {
- // return FindTopDocuments(raw_query, [](int document_id, DocumentStatus status, int rating) { return status == DocumentStatus::ACTUAL; });
- // }
- template <typename DocumentPredicate>
- [[nodiscard]] bool FindTopDocuments(const string& raw_query, DocumentPredicate document_predicate,
- vector<Document>& result) const {
- Query query;
- bool query_parsing_result = ParseQuery(raw_query, query);
- if (!query_parsing_result) {
- return false;
- }
- //const Query query = ParseQuery(raw_query);
- auto matched_documents = FindAllDocuments(query, document_predicate);
- sort(matched_documents.begin(), matched_documents.end(),
- [](const Document& lhs, const Document& rhs) {
- if (abs(lhs.relevance - rhs.relevance) < std::numeric_limits<double>::epsilon()) {
- return lhs.rating > rhs.rating;
- }
- return lhs.relevance > rhs.relevance;
- });
- if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
- matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
- }
- // return matched_documents;
- if (matched_documents.empty()) {
- return false;
- }
- result = matched_documents;
- return true;
- }
- [[nodiscard]] bool FindTopDocuments(const string& raw_query, DocumentStatus status,
- vector<Document>& result) const {
- if (FindTopDocuments(
- raw_query, [status](int document_id, DocumentStatus document_status, int rating) {
- return document_status == status;
- }, result)) {
- return true;
- }
- return false;
- }
- [[nodiscard]] bool FindTopDocuments(const string& raw_query, vector<Document>& result) const {
- DocumentStatus status = DocumentStatus::ACTUAL;
- if (FindTopDocuments(
- raw_query, [status](int document_id, DocumentStatus document_status, int rating) {
- return document_status == status;
- }, result)) {
- return true;
- }
- return false;
- }
- int GetDocumentCount() const {
- return documents_.size();
- }
- [[nodiscard]] bool MatchDocument(const string& raw_query, int document_id,
- tuple<vector<string>, DocumentStatus>& result) const {
- //const Query query = ParseQuery(raw_query);
- Query query;
- bool query_parsing_result = ParseQuery(raw_query, query);
- if (!query_parsing_result) {
- return false;
- }
- vector<string> matched_words;
- for (const string& word : query.plus_words) {
- if (word_to_document_freqs_.count(word) == 0) {
- continue;
- }
- if (word_to_document_freqs_.at(word).count(document_id)) {
- matched_words.push_back(word);
- }
- }
- for (const string& word : query.minus_words) {
- if (word_to_document_freqs_.count(word) == 0) {
- continue;
- }
- if (word_to_document_freqs_.at(word).count(document_id)) {
- matched_words.clear();
- break;
- }
- }
- //return {matched_words, documents_.at(document_id).status};
- if (matched_words.empty()) {
- return false;
- }
- result = {matched_words, documents_.at(document_id).status};
- return true;
- }
- int GetDocumentId(int index) const {
- if ((index<0 || index >= document_count_) || document_index_.empty()){
- // cerr << "Индекс переданного документа выходит за пределы допустимого диапазона (0; количество документов)"s << endl;
- return SearchServer::INVALID_DOCUMENT_ID;
- } else{
- return document_index_.at(index);
- }
- }
- private:
- struct DocumentData {
- int rating;
- DocumentStatus status;
- };
- set<string> stop_words_;
- map<string, map<int, double>> word_to_document_freqs_;
- map<int, DocumentData> documents_;
- 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)) {
- // if (!IsValidWord(word)){
- // cerr << "Документ содержит недопустимы символы" << endl;
- // }
- words.push_back(word);
- }
- }
- return words;
- }
- static int ComputeAverageRating(const vector<int>& ratings) {
- if (ratings.empty()) {
- return 0;
- }
- //cd int rating_sum = accumulate(ratings.begin(), ratings.end(), 0);
- // for (const int rating : ratings) {
- // rating_sum += rating;
- // }
- return accumulate(ratings.begin(), ratings.end(), 0) / static_cast<int>(ratings.size());
- }
- static bool IsValidWord(const string& word) {
- // A valid word must not contain special characters
- return none_of(word.begin(), word.end(), [](char c) {
- return c >= '\0' && c < ' ';
- });
- }
- struct QueryWord {
- string data;
- bool is_minus;
- bool is_stop;
- };
- [[nodiscard]] bool ParseQueryWord(string text, QueryWord& result) const {
- bool is_minus = false;
- // Word shouldn't be empty
- if (text[0] == '-') {
- is_minus = true;
- text = text.substr(1);
- }
- if (text.empty()){
- // cerr << "Задано пустое минус-слово кот -"s << endl;
- return false;
- }
- if (text.at(0) == '-'){
- // cerr << "Минус слова заданы не верно --кот"s << endl;
- return false;
- }
- result.data = text;
- result.is_minus = is_minus;
- result.is_stop = IsStopWord(text);
- // return {text, is_minus, IsStopWord(text)};
- return true;
- }
- struct Query {
- set<string> plus_words;
- set<string> minus_words;
- };
- int document_count_ = 0;
- std::vector <int> document_index_;
- [[nodiscard]] bool ParseQuery(const string& text, Query &parse_query_result) const {
- //Query query;
- for (const string& word : SplitIntoWords(text)) {
- if (!IsValidWord(word)){
- return false;
- // cerr << "Некорректный символ в запросе"s << endl;
- }
- QueryWord query_word;
- bool query_parsing_result = ParseQueryWord(word, query_word);
- if (!IsValidWord(query_word.data) || !query_parsing_result) {
- return false;
- }
- if (!query_word.is_stop) {
- if (query_word.is_minus) {
- parse_query_result.minus_words.insert(query_word.data);
- } else {
- parse_query_result.plus_words.insert(query_word.data);
- }
- }
- }
- //return query;
- return true;
- }
- // Existence required
- double ComputeWordInverseDocumentFreq(const string& word) const {
- return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
- }
- // Шаблонная функция с функциональным параметром
- template <typename Predicate>
- vector<Document> FindAllDocuments(const Query& query, Predicate predicate) const {
- map<int, double> document_to_relevance;
- for (const string& word : query.plus_words) {
- if (word_to_document_freqs_.count(word) == 0) {
- continue;
- }
- const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
- for (const auto &[document_id, term_freq] : word_to_document_freqs_.at(word)) {
- // Будем считать TF-IDF только для документов, удовлетвлетворяющие предикату
- auto doc_status = documents_.at(document_id).status;
- auto doc_rating = documents_.at(document_id).rating;
- if (predicate(document_id, doc_status, doc_rating)) {
- document_to_relevance[document_id] += term_freq * inverse_document_freq;
- }
- }
- }
- for (const string& word : query.minus_words) {
- if (word_to_document_freqs_.count(word) == 0) {
- continue;
- }
- for (const auto &[document_id, _] : word_to_document_freqs_.at(word)) {
- document_to_relevance.erase(document_id);
- }
- }
- vector<Document> matched_documents;
- for (const auto &[document_id, relevance] : document_to_relevance) {
- matched_documents.push_back(
- {document_id, relevance, documents_.at(document_id).rating});
- }
- return matched_documents;
- }
- };
- void PrintDocument(const Document& document) {
- cout << "{ "s
- << "document_id = "s << document.id << ", "s
- << "relevance = "s << document.relevance << ", "s
- << "rating = "s << document.rating
- << " }"s << endl;
- }
- int main() {
- SearchServer search_server("и в на"s);
- // Явно игнорируем результат метода AddDocument, чтобы избежать предупреждения
- // о неиспользуемом результате его вызова
- (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;
- }
- // vector<Document> documents;
- // if (search_server.FindTopDocuments("--пушистый"s, documents)) {
- // for (const Document& document : documents) {
- // PrintDocument(document);
- // }
- // } else {
- // cout << "Ошибка в поисковом запросе"s << endl;
- // }
- vector<Document> documents;
- if (search_server.FindTopDocuments(" на"s, documents)) {
- for (const Document& document : documents) {
- PrintDocument(document);
- }
- } else {
- cout << "Ошибка в поисковом запросе"s << endl;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement