Эй, у меня проблемы с вычислением кода для подсчета количества уникальных слов. Мой мыслительный процесс с точки зрения psudeocode сначала делал вектор, так что-то вроде vector<string> unique_word_list;
Тогда я получал бы программу для чтения каждой строки, чтобы у меня было что-то вродеwhile(getline(fin,line))
, Для меня труднее всего придумать код, в котором я проверяю вектор (массив), чтобы увидеть, есть ли уже там строка. Если он там, я просто увеличиваю количество слов (достаточно просто), но если его там нет, тогда я просто добавляю новый элемент в вектор. Я был бы очень признателен, если бы кто-нибудь мог помочь мне здесь. Я чувствую, что это не сложно, но по какой-то причине я не могу придумать код для сравнения строки с тем, что находится внутри массива, и определения, является ли это уникальным словом или нет.
Не используйте vector
— используйте контейнер, который поддерживает уникальность, например std::set
или же std::unordered_set
. Просто преобразуйте строку в нижний регистр (используя std::tolower
) прежде чем добавить его:
std::set<std::string> words;
std::string next;
while (file >> next) {
std::transform(next.begin(), next.end(), next.begin(), std::tolower);
words.insert(next);
}
std::cout << "We have " << words.size() << " unique words.\n"
Не могу помочь себе написать ответ, который использует красивую библиотеку C ++. Я бы сделал это так, с std::set
:
#include <algorithm>
#include <cctype>
#include <string>
#include <set>
#include <fstream>
#include <iterator>
#include <iostream>
int main()
{
std::ifstream ifile("test.txt");
std::istream_iterator<std::string> it{ifile};
std::set<std::string> uniques;
std::transform(it, {}, std::inserter(uniques, uniques.begin()),
[](std::string str) // make it lower case, so case doesn't matter anymore
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
return str;
});
// display the unique elements
for(auto&& elem: uniques)
std::cout << elem << " ";
// display the size:
std::cout << std::endl << uniques.size();
}
Вы также можете определить новый тип строки, в которой вы измените char_traits
поэтому сравнение становится без учета регистра. Это тот код, который вам нужен (гораздо более длинный, чем раньше, но в конечном итоге вы можете использовать его повторно), перегрузка char_traits копируется / вставляется из cppreference.com:
#include <algorithm>
#include <cctype>
#include <string>
#include <set>
#include <fstream>
#include <iterator>
#include <iostream>
struct ci_char_traits : public std::char_traits<char> {
static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); }
static int compare(const char* s1, const char* s2, size_t n) {
while ( n-- != 0 ) {
if ( toupper(*s1) < toupper(*s2) ) return -1;
if ( toupper(*s1) > toupper(*s2) ) return 1;
++s1; ++s2;
}
return 0;
}
static const char* find(const char* s, int n, char a) {
while ( n-- > 0 && toupper(*s) != toupper(a) ) {
++s;
}
return s;
}
};
using ci_string = std::basic_string<char, ci_char_traits>;
// need to overwrite the insertion and extraction operators,
// otherwise cannot use them with our new type
std::ostream& operator<<(std::ostream& os, const ci_string& str) {
return os.write(str.data(), str.size());
}
std::istream& operator>>(std::istream& os, ci_string& str) {
std::string tmp;
os >> tmp;
str.assign(tmp.data(), tmp.size());
return os;
}
int main()
{
std::ifstream ifile("test.txt");
std::istream_iterator<ci_string> it{ifile};
std::set<ci_string> uniques(it, {}); // that's it
// display the unique elements
for (auto && elem : uniques)
std::cout << elem << " ";
// display the size:
std::cout << std::endl << uniques.size();
}