Основная проблема в вашем подходе заключается в том, что вы используете второй цикл для сбора информации о словах, и при этом вы потеряли всю информацию о том, в каких строках слова.
Вместо того, чтобы пытаться выяснить, на какой линии вы находитесь во втором цикле, у вас есть вся информация, необходимая для текущей строки в первом цикле.Все, что вам нужно, это переменная, которая отслеживает каждую строку.Вы используете (неправильно я могу добавить) std::getline
- каждый раз, когда вы вызываете эту функцию, вы переходите на следующую строку, поэтому вы неявно знаете, на какой строке вы находитесь в первом цикле.
Во-первых, вам нужно исправить цикл чтения так, чтобы он правильно читал строки из файла:
std::string line;
while (std::getline(in, line))
{
//...
}
Во-вторых, внутри цикла while
вы можете определить всю информациювам нужно слово, количество слов и строки, где слово найдено.Для этого вам не нужны два цикла.
Вместо std::map<std::string, int>
, который знает только количество слов, вы можете создать карту, содержащую всю информацию - количество слов и строка (и), в которой найдено слово.Вот тип карты, который может содержать эту информацию:
std::map<std::string, std::pair<int, std::set<int>>>
«Вторая» карты содержит информацию о счете, и std::set
, который будет содержать всеномера строк, где слово найдено.Причина std::set
состоит в том, чтобы гарантировать, что повторяющиеся номера строк не будут сохранены.
Собирая все это вместе, вот пример программы, использующей этот тип:
#include <map>
#include <set>
#include <string>
#include <sstream>
#include <iostream>
// pair and map type
using WordInfo = std::pair<int, std::set<int>>;
using WordMap = std::map<std::string, WordInfo>;
int main()
{
// our map
WordMap wm;
std::string line;
// the line count
int line_number = 1;
while (std::getline(std::cin, line))
{
// line parser
std::istringstream strm(line);
std::string word;
while ( strm >> word)
{
// we call map::insert, not `[ ]` to insert into a map
auto pr = wm.insert({word, {0,std::set<int>()}});
// the return value of map::insert gives us a pair, where the first is
// an iterator to the item in the map
auto& mapIter = pr.first;
// increment the word count
++(mapIter->second.first);
// insert the line number into the set
mapIter->second.second.insert(line_number);
}
// increment the line counter
++line_number;
}
// output results
for (auto& m : wm )
{
std::cout << "The word \"" << m.first << "\" appears " << m.second.first << " times on the following lines:\n";
for ( auto& m2 : m.second.second)
std::cout << m2 << " ";
std::cout << "\n\n";
}
}
Так чтобыло сделано здесь?
1) Строка, в которой включено каждое слово, известна в цикле чтения.Все, что нужно сделать, это увеличить счетчик строк для каждой строки, которая читается.
2) Мы используем std::map::insert
, чтобы вставить запись в карту, а не std::map::operator[ ]
,Причина в том, что map::insert
не будет вставлять запись, если запись уже существует, она будет вставлять новую запись, если запись не существует, и независимо от того, что сделано, std::map::insert
возвращает итератор для элемента вкарта.
Нам понадобится возвращенный нам итератор для дальнейшей обработки.В последующих строках мы просто увеличиваем счет и обновляем std::set
.
Вот живой пример .
Примечание: я понятия не имеючто все заменители вы делаете в своей исходной программе, поэтому я пропустил все это и сконцентрировался исключительно на задаче определения слов и строки (ий) слов.