#c #stl #map #set
#c #stl #словарь #установить
Вопрос:
Я знаю, что такое map
и его общие базовые функции, но я не знаю, почему здесь используется a set
вместо того, чтобы просто объявить int i = value
или что-то подобное.
Что я действительно пытаюсь сделать, так это: после помещения слова в вектор я хочу использовать то же слово и в качестве ключа к значению. Но я действительно не знаю всей цели использования map
для этого. Не уверен, что я даю достаточно информации, но просто спросите, что вам нужно еще, и я отвечу.
Я предоставил только readWords
функцию, но если кому-то нужен полный код, включая заголовок, класс и основной файл, тогда я могу их также разместить.
У меня частично есть код, записанный там, со справкой, но я, честно говоря, не знаю, что он делает после push_back()
функции.
/* Read word-by-word from filename and store words in text vector.
* Also use normalized version of word as key in concordance map
* The value associated with each key in the map is a set whose
* keys are the associated indices into the vector.
*/
void Concordance::readWords(char * filename){
ifstream fin(filename, ifstream::in);
if (fin.is_open()){
while(!fin.eof()){
string word;
fin >> word;
normalize(word);
text.push_back(word); //puts word into vector
set<int> seat;
seat.insert(text.size()-1);
pair<string, set<int> > pear;
concordance.insert(pear);
}
}
else{
cerr << "Unable to open file datafile.txt";
exit(1); // call system to stop
}
fin.close(); //closes the filename
}
Ответ №1:
Я не думаю, что вы полностью понимаете требования к этому алгоритму. (Кстати, это домашнее задание?)
Цель здесь состоит в том, чтобы создать соответствие — список всех вхождений каждого слова. Цель set
состоит в том, чтобы сохранить все вхождения. (Например: слово «apple» может появиться на страницах 1, 73 и 100. Таким образом, запись в сопоставлении для «apple» должна содержать все эти значения.)
Цель нормализации состоит в том, чтобы сэкономить читателю время согласования: «apple», «Яблоко» и «apples», вероятно, должны быть в одной записи на карте.
Понимая это, мы можем обновить вашу программу.
Во-первых, никогда не проверяйте, eof
прежде чем читать данные. Имеет смысл проверять это только после того, как вы прочитаете данные. На самом деле, существует гораздо более простая идиома для этой проверки:
string word;
while (fin >> word) {
...
Мне кажется, что от нас требуется сохранить исходное слово в векторе, а затем использовать нормализованное слово в качестве индекса сопоставления
text.push_back(word);
normalize(word);
Теперь обновить сопоставление проще простого. Вам не нужен pair
, просто используйте []
оператор. Поймите, что простая ссылка на запись карты приводит к ее появлению!
concordance[word].insert(text.size()-1);
РЕДАКТИРОВАТЬ, разбивая этот последний бит на части:
concordance[word]
ищет запись, проиндексированную word
в сопоставлении. Если запись существует, она возвращается. Если запись не завершается, она создается, и возвращается вновь сформированная запись. .insert
это операция вставки в набор, расположенный рядом с элементом карты, индексируемым word
. text.size()-1
это значение, вставленное в набор, расположенный в записи карты, проиндексированной word
.
Собирая его обратно, concordance[word].insert(text.size()-1)
просматривает сопоставление, извлекает (или создает) указанное set
, а затем вставляет число text.size()-1
в этот набор.
Вот так!
Комментарии:
1. Итак, согласование [word].insert(text.size() -1); вставляет ли ‘word’ в сопоставление согласований, а затем вставляет размер текста? Мне также не нужно объявлять новый набор?
2. Да,
concordance[word].insert(text.size()-1);
это вставкаword
в сопоставление совпадений, а затем вставкаtext.size()-1
в набор. Вам не нужно объявлять новый набор.3. Спасибо за подробное объяснение! Я бы проголосовал за вас, если бы мог. 😀
Ответ №2:
Я не уверен, допустили ли вы ошибку при копировании кода, или код был преднамеренно таким, но seat
набор не используется (для чего-либо другого, кроме вставки элемента, но поскольку он не прочитан / сохранен, он будет потерян), и все элементы, добавленные в concordance
, будут парами ("",[empty set])
Не похоже, что он пытается создать индекс, то есть сопоставление слов с позициями в векторе, где появляется слово. Если это так, вероятно, было бы лучше, если бы это было сделано как:
std::map<std::string, std::set<int> > concordance;
//...
concordance[word].insert(text.size()-1); // if it does not exists, it will create it
// if it exists it will retrieve it and
// add the new position
Этот шаблон является общим для индексации слов на страницах (например, для книги), где набор имеет преимущество перед, скажем, вектором, в том, что он гарантирует уникальность, если слово встречается 100 раз на одной странице, набор гарантирует, что номер страницы не повторяется (вам придется проверить это в векторе). Это не относится к коду, поскольку индексы относятся к позициям в векторе слов, которые уникальны сами по себе.
Также обратите внимание, как указывает Наваз, что цикл нуждается в некоторых исправлениях.
Ответ №3:
Прежде всего, ваш while
цикл неправильный, потому что eof
флаг (или любой другой флаг сбоя) устанавливается после неудачной попытки чтения из потока; это означает, что если попытка чтения завершается неудачей, вы пытаетесь вставить ранее прочитанное word
в вектор дважды, а остальной код в цикле все еще выполняется, хотя на самом деле не должен.
Более идиоматичным циклом while было бы следующее:
string word;
while( fin >> word ){
normalize(word);
text.push_back(word); //puts word into vector
set<int> seat;
seat.insert(text.size()-1);
pair<string, set<int> > pear;
concordance.insert(pear);
}
Если попытка чтения (т.е. fin >> word
) завершается неудачей, то возвращаемое std::istreamamp;
неявно преобразуется в false
, и цикл завершается.
И я не совсем понял остальную часть вашего поста, вопрос и что именно вы пытаетесь сделать, поэтому я не могу это комментировать.