Вектор струн со счетчиком Stack Overflow

Я ввожу файл символов, и каждое слово получает свое место в векторе. Затем мне нужно отслеживать каждое слово и выяснять, сколько раз каждое уникальное слово появлялось так, что:

Есть три дерева деревья деревья

должен вывести:

Там 1
1
три 1
деревья 3

Мне было интересно, как использовать вектор строк, чтобы сохранить тракт каждого слова.
Я сделал бы вектор строк с каждой строкой, имеющей вектор единственного целого?

0

Решение

Не забивайте гвоздь отверткой. std::vector, не особенно полезен для этой задачи в ее самой основной форме: простой расчет частоты. Для произвольного ввода из стандартного ввода лучше всего использовать ассоциативный контейнер, где ключ — это строка ввода, а значение — накопленная частота.

Расчет неупорядоченной частоты

Неупорядоченный класс отображения, std::unordered_map, ввод на std::string и отображение на частотомер для этой строки, может использоваться для отслеживания базовой частоты. Например:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>

int main()
{
std::unordered_map<std::string, unsigned> m;
std::string word;
while (std::cin >> word)
++m[word]; // increment the count for this word

for (auto const& pr : m)
std::cout << pr.first << ':' << pr.second << '\n';
}

Лексикографическая упорядоченная частота

Примечание: нет конкретных порядок использовать ассоциативный контейнер std::unordered_map (отсюда и название). Если вы хотите лексикографический порядок, вы можете просто использовать обычный std::map. такие как:

#include <iostream>
#include <vector>
#include <string>
#include <map>

int main()
{
std::map<std::string, unsigned> m;
std::string word;
while (std::cin >> word)
++m[word];

for (auto const& pr : m)
std::cout << pr.first << ':' << pr.second << '\n';
}

Расчет частоты удержания положения

Поддержание того, где во входном потоке появляется слово при расчете счетчика частоты, также возможно, и занимает немного больше кода. Выберите неупорядоченный или упорядоченный ассоциативный контейнер, как мы делали раньше, но вместо сопоставления с unsignedмы сопоставляем с std::vector<unsigned>, где мы накапливаем счетчик слов при потреблении входных слов. Общий размер каждого вектора все еще сохраняет счетчик частоты, но сам вектор сохраняет позицию во входном потоке, в котором появляется соответствующее слово. Например:

#include <iostream>
#include <vector>
#include <string>
#include <map>

int main()
{
std::map<std::string, std::vector<unsigned int>> m;
std::string word;
unsigned ctr = 0;
while (std::cin >> word)
m[word].push_back(++ctr);

for (auto const& pr : m)
{
std::cout << pr.first << ':' << pr.second.size() << " { ";
for (auto pos : pr.second)
std::cout << pos << ' ';
std::cout << "}\n";
}
}

Это произведет вывод формы:

word : frequency { n1 n2 n3... }

где word это отличное слово, frequency общая частота во входном потоке, и n1,n2,n3,... являются позициями (начиная с 1), где слово появилось во время обработки.

Надеюсь, один из этих методов полезен.

2

Другие решения

Вы можете использовать мультимножество классов из c ++, которое будет отслеживать, сколько раз вы добавляли каждое слово в набор. Также имейте в виду, что вы можете читать полные слова из потоков в c ++, и он будет автоматически пропускать любые пробелы.

Я буду читать из stdin для этого примера (обратите внимание, я не скомпилировал это, просто чтобы показать идею).

#include <set>
using namespace std;

int main(){
string word;
multiset<string> ocurrences;
while(cin >> word){
ocurrences.insert(word);
}
for(string w : ocurrences){  // Iterate over all words in the set
cout<<w<<" "<<counts.count(w)<<" ";
}
}

Как уже упоминалось в комментариях, если вы хотите напечатать слова в порядке первого вхождения, просто сохраните vector<string> и добавьте каждое прочитанное слово, если его еще нет в наборе, а затем выполните итерацию по этому вектору вместо набора.

#include <set>
using namespace std;

int main(){
string word;
vector<string> words;
multiset<string> ocurrences;
while(cin >> word){
if(ocurrences.count(word) == 0) //Is this the first time we see this word?
words.push_back(word);
ocurrences.insert(word);
}
for(string w : words){ //Iterate over the words in the order
//they appeared in the input.
cout<<w<<" "<<ocurrences.count(w)<<" ";
}
}

Другое дело, что хотя мультимножество лучше подходит для решения этой конкретной проблемы, то, о чем вы спрашиваете в своем вопросе, называется картой, структурой данных, которая связывает ключ со значением (возможно, разных типов). C ++ уже имеет реализацию карты. В этом случае вам понадобится map<string, int> связать каждое слово со временем, когда оно встречается.

0

Вот способ, которым вы можете сделать это, накапливая свой словарь по потоку слов и используя структурированные привязки C ++ 17:

int main()
{
std::istringstream words( "There are three trees trees trees" );

auto dic = std::accumulate(
std::istream_iterator< std::string >( words ) ,
std::istream_iterator< std::string >( ) ,
std::unordered_map< std::string , int >( ) ,
[]( auto && map , auto && word ) -> decltype( auto )
{
auto [ it , success ] = map.try_emplace(
std::forward< decltype( word ) >( word ) , 0 );

++ it->second;

return std::forward< decltype( map ) >( map );
} );

for ( const auto & [ key , value ] : dic )
{
std::cout << key << ": " << value << std::endl;
}
}

Жить в Колиру (хотя с некоторыми предупреждениями)

> trees: 3
> three: 1
> There: 1
> are: 1
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector