Вместо того, чтобы пытаться использовать базовый массив строк, вам понадобится какой-то способ отслеживать количество раз, которое видно каждое слово. Вы можете использовать простой struct
или std::map
. В любом случае вы можете связать слово и количество раз, которое оно рассматривается как один объект. Если вы затем соберете всю структуру, содержащую слово и число в std::vector
, в отличие от базового массива, вы можете предоставить простую функцию сравнения, чтобы использовать std::sort
для сортировки вектора по слову, сохраняя при этом связь счетчика скаждое слово.
Используя подход stuct
, вы можете создать структуру, содержащую std::string
и счетчик, такой как:
struct wordcount { /* struct holding word and count */
std::string word;
size_t count;
};
Для функции сравнениячтобы отсортировать вектор wordcount
по word
, вы можете использовать простое:
/* compare function to sort vector of struct by words */
bool cmp (const wordcount& a, const wordcount& b)
{
return a.word < b.word;
}
Используя структуру, вам нужно будет перебрать слова, которые вы видели до сих пор, чтобы определить, просто ли вынеобходимо увеличить count
на существующем слове или добавить новую структуру wordcount
к вашему вектору с помощью count = 1;
. Чтобы сделать функцию полезной, вы можете сделать так, чтобы она возвращала индекс в векторе (слабо эквивалентный индексув массиве), если слово уже существует, или верните -1
, если его нет.
/* interate over each struct in vector words to find word */
int findword (const std::vector<wordcount>& words,
const std::string& word)
{
for (auto w = words.begin(); w != words.end(); w++)
if (w->word == word) /* if word found */
return w - words.begin(); /* return index */
return -1; /* return word not found */
}
На основе возврата вы можете либо увеличить count
в индексе, либодд новый wordcount
в ваш вектор. Короткая реализация, использующая вышеизложенное, будет выглядеть так:
int main (int argc, char **argv) {
if (argc < 2) { /* validate filename given as argument */
std::cerr << "error: insufficient input.\n"
<< "usage: " << argv[0] << "<filename>\n";
return 1;
}
std::string word; /* string to hold word */
std::vector<wordcount> words {}; /* vector of struct wordcount */
std::fstream f (argv[1]); /* file stream */
while (f >> word) { /* read each word from file */
int idx = findword (words, word); /* alread exists, get index */
if (idx != -1) { /* if index found */
words[idx].count++; /* increment count */
}
else { /* otherwise new word */
wordcount tmp = {word, 1}; /* initialize struct */
words.push_back(tmp); /* add to vector */
}
}
std::sort (words.begin(), words.end(), cmp); /* sort by words */
for (auto& w : words) /* output results */
std::cout << w.word << " " << w.count << '\n';
}
Если сложить все вышеперечисленные части вместе, вы получите:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
struct wordcount { /* struct holding word and count */
std::string word;
size_t count;
};
/* compare function to sort vector of struct by words */
bool cmp (const wordcount& a, const wordcount& b)
{
return a.word < b.word;
}
/* interate over each struct in vector words to find word */
int findword (const std::vector<wordcount>& words,
const std::string& word)
{
for (auto w = words.begin(); w != words.end(); w++)
if (w->word == word) /* if word found */
return w - words.begin(); /* return index */
return -1; /* return word not found */
}
int main (int argc, char **argv) {
if (argc < 2) { /* validate filename given as argument */
std::cerr << "error: insufficient input.\n"
<< "usage: " << argv[0] << "<filename>\n";
return 1;
}
std::string word; /* string to hold word */
std::vector<wordcount> words {}; /* vector of struct wordcount */
std::fstream f (argv[1]); /* file stream */
while (f >> word) { /* read each word from file */
int idx = findword (words, word); /* alread exists, get index */
if (idx != -1) { /* if index found */
words[idx].count++; /* increment count */
}
else { /* otherwise new word */
wordcount tmp = {word, 1}; /* initialize struct */
words.push_back(tmp); /* add to vector */
}
}
std::sort (words.begin(), words.end(), cmp); /* sort by words */
for (auto& w : words) /* output results */
std::cout << w.word << " " << w.count << '\n';
}
Пример использования / Вывод
Если вы используете образец ввода, вы получите.
$ ./bin/wordcount dat/webpage.txt
Computer 1
algorithm 1
analysis 1
and 1
computer 3
department 1
design 2
quantum 1
science 1
system 1
Существует множество способов решить проблему этого типа. Это можно сделать с простыми старыми массивами, но тогда вы будете отслеживать слова и считать в каком-то отдельном массиве (или массивах), а затем либо написать свой собственный вид (или использовать C qsort
в одном массиве, содержащем слова изатем сопоставьте счет обратно с отсортированным выводом с копией оригинала и вашего массива счетчиков). Ключ, независимо от используемого вами подхода, заключается в том, что у вас должен быть способ сохранить предварительную сортировку между словами и количество раз, которое они каждый видят с результатом пост-сортировки ваших слов, а затем способ отобразить обратные отсчеты. на правильное слово. Использование объекта, который связывает слово и считается как единое целое, решает проблему ассоциации.
Посмотрите вещи, примите их как один из способов приблизиться к нему. Дайте мне знать, если у вас есть дополнительные вопросы.