Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cmath>
- #include <map>
- #include <string>
- #include <algorithm>
- #include <iostream>
- #include <set>
- #include <utility>
- #include <vector>
- #include <numeric>
- #include <chrono>
- using namespace std;
- const int MAX_RESULT_DOCUMENT_COUNT = 5;
- enum class DocumentStatus{
- ACTUAL,
- IRRELEVANT,
- BANNED,
- REMOVED
- };
- 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{
- int id;
- double relevance;
- int rating;
- };
- class SearchServer{
- public:
- void SetStopWords(const string &text){
- for(const string &word : SplitIntoWords(text)){
- stop_words_.insert(word);
- }
- }
- void AddDocument(const int &document_id, const string &document, DocumentStatus status, const vector<int> &ratings){
- ++document_count_;
- vector<string> ex_doc = SplitIntoWordsNoStop(document);
- double counted = (double)ex_doc.size();
- for(const auto &word : ex_doc){
- word_to_document_freqs_[word].insert({document_id,count(ex_doc.begin(), ex_doc.end(), word) / counted});
- }
- if(!ratings.empty()){
- document_ratings_[document_id].rating = ComputeAverageRating(ratings);
- document_ratings_[document_id].status = status;
- } else{
- document_ratings_[document_id].rating = 0;
- document_ratings_[document_id].status = status;
- }
- //document_ratings_[document_id] = {ComputeAverageRating(ratings),status};
- //document_ratings_.emplace(document_id, Status{ComputeAverageRating(ratings), status});
- }
- template<typename FuncPredict>
- auto FindTopDocuments(const string &raw_query, FuncPredict predict) const{
- const double EPSILON = 1e-6;
- const Query query_words = ParseQuery(raw_query);
- vector<Document> matched_documents;
- if constexpr(is_same_v<FuncPredict, DocumentStatus>){
- matched_documents = FindAllDocuments(query_words, predict);
- }else{
- matched_documents = FindAllDocuments(query_words, DocumentStatus::BANNED);
- }
- sort(matched_documents.begin(), matched_documents.end(),
- [EPSILON](const Document &lhs, const Document &rhs){
- if(abs(lhs.relevance - rhs.relevance) < EPSILON)
- return lhs.rating > rhs.rating;
- else
- return lhs.relevance > rhs.relevance;
- }
- );
- if(matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT){
- matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
- }
- return matched_documents;
- }
- vector<Document> FindTopDocuments(const string &raw_query, DocumentStatus status = DocumentStatus::ACTUAL) const{
- return FindTopDocuments(raw_query,status);
- }
- auto FindTopDocuments(const string &raw_query) const{
- return FindTopDocuments(raw_query,
- [](int document_id, DocumentStatus status, int rating){
- return status == DocumentStatus::ACTUAL;
- }
- );
- }
- int GetDocumentCount() const{return document_count_;};
- tuple<vector<string>, DocumentStatus> MatchDocument(const string &raw_query, int document_id) const{
- vector<string> matched_words;
- for(const string &word : ParseQuery(raw_query).plus_words)
- if(word_to_document_freqs_.count(word))
- if(word_to_document_freqs_.at(word).count(document_id))
- matched_words.push_back(word);
- for(const string &word : ParseQuery(raw_query).minus_words)
- if(word_to_document_freqs_.count(word))
- if(word_to_document_freqs_.at(word).count(document_id)){
- matched_words.clear();
- break;
- }
- return{matched_words, document_ratings_.at(document_id).status};
- };
- private:
- struct Query{
- set<string> plus_words;
- set<string> minus_words;
- };
- struct Status{
- int rating;
- DocumentStatus status;
- };
- map<string, map<int, double>> word_to_document_freqs_;
- set<string> stop_words_;
- int document_count_ = 0;
- map<int, Status> document_ratings_;
- vector<string> SplitIntoWordsNoStop(const string &text) const{
- vector<string> words;
- for(const string &word : SplitIntoWords(text)){
- if(!(stop_words_.count(word) > 0)){
- words.push_back(word);
- }
- }
- return words;
- }
- Query ParseQueryWord(const set<string> &text) const{
- Query query;
- for(auto &word : text){
- if(word[0] == '-'){
- query.minus_words.insert(word.substr(1));
- } else{
- query.plus_words.insert(word);
- }
- }
- return query;
- }
- Query ParseQuery(const string &text) const{
- set<string> query_words;
- for(const string &word : SplitIntoWordsNoStop(text)){
- query_words.insert(word);
- }
- return ParseQueryWord(query_words);
- }
- template<typename FuncPredict>
- vector<Document> FindAllDocuments(const Query &query_words, FuncPredict predict)const{
- vector<Document> matched_documents;
- map<int, double> document_to_relevance;
- for(const auto &query_word : query_words.plus_words){
- if(word_to_document_freqs_.count(query_word)){
- for(const auto &[id,tf] : word_to_document_freqs_.at(query_word)){
- if(predict(id, document_ratings_.at(id).status, document_ratings_.at(id).rating)){
- document_to_relevance[id] += log(document_count_ / (double)word_to_document_freqs_.at(query_word).size()) * tf;
- }
- }
- }
- }
- for(const auto &query_word : query_words.minus_words){
- if(word_to_document_freqs_.count(query_word)){
- for(const auto &[id, tf] : word_to_document_freqs_.at(query_word)){
- document_to_relevance.erase(id);
- }
- }
- }
- for(const auto &[document_id, relevance] : document_to_relevance){
- matched_documents.push_back({document_id,relevance,document_ratings_.at(document_id).rating});
- }
- return matched_documents;
- }
- static int ComputeAverageRating(const vector<int> &ratings){
- int sum = 0;
- if(ratings.size() == 0){
- return 0;
- } else{
- for(const int &number : ratings)
- sum += number;
- return sum / (int)ratings.size();
- }
- return 0;
- }
- };
- 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;
- search_server.SetStopWords("и в на"s);
- search_server.AddDocument(0, "белый кот и модный ошейник"s, DocumentStatus::ACTUAL, {8, -3});
- search_server.AddDocument(1, "пушистый кот пушистый хвост"s, DocumentStatus::ACTUAL, {7, 2, 7});
- search_server.AddDocument(2, "ухоженный пёс выразительные глаза"s, DocumentStatus::ACTUAL, {5, -12, 2, 1});
- search_server.AddDocument(3, "ухоженный скворец евгений"s, DocumentStatus::BANNED, {9});
- cout << "ACTUAL by default:"s << endl;
- for (const Document& document : search_server.FindTopDocuments("пушистый ухоженный кот"s)) {
- PrintDocument(document);
- }
- cout << "BANNED:"s << endl;
- for (const Document& document : search_server.FindTopDocuments("пушистый ухоженный кот"s, DocumentStatus::BANNED)) {
- PrintDocument(document);
- }
- cout << "Even ids:"s << endl;
- for (const Document& document : search_server.FindTopDocuments("пушистый ухоженный кот"s, [](int document_id, DocumentStatus status, int rating) { return document_id % 2 == 0; })) {
- PrintDocument(document);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment