Выбрать главу

vectorstring *text_words = text_locations-first;

vectorlocation *text_locs = text_locations-second;

Теперь нам надо синхронно обойти оба вектора, учитывая два случая:

* слово встретилось впервые. Нужно поместить в map новую пару ключ/значение;

* слово встречается повторно. Нам нужно обновить вектор позиций, добавив дополнительную пару (номер строки, номер колонки).

Вот текст функции:

register int elem_cnt = text_words-size();

for ( int ix=0; ix elem_cnt; ++ix )

{

string textword = ( *text_words )[ ix ];

// игнорируем слова короче трех букв

// или присутствующие в списке стоп-слов

if ( textword.size() 3 ||

exclusion_set.count( textword ))

continue;

// определяем, занесено ли слово в отображение

// если count() возвращает 0 - нет: добавим его

if ( ! word_map-count((*text_words)[-ix] ))

{

loc *ploc = new vectorlocation;

ploc-push_back( (*text_locs) [ix] );

word_map-insert(value_type((*text_words)[ix],ploc));

}

else

// добавим дополнительные координаты

(*word_map)[(*text_words)[ix]]-

push_back((*text_locs)[ix]);

}

Синтаксически сложное выражение

(*word_map)[(*text_words)[ix]]-

push_back((*text_locs)[ix]);

будет проще понять, если мы разложим его на составляющие:

// возьмем слово, которое надо обновить

string word = (*text_words) [ix];

// возьмем значение из вектора позиций

vectorlocation *ploc = (*word_map) [ word ];

// возьмем позицию - пару координат

loc = (*text_locs)[ix];

// вставим новую позицию

ploc-push_back(loc);

Выражение все еще остается сложным, так как наши векторы представлены указателями. Поэтому вместо употребления оператора взятия индекса:

string word = text_words[ix]; // ошибка

мы вынуждены сначала разыменовать указатель на вектор:

string word = (*text_words) [ix]; // правильно

В конце концов build_word_map() возвращает построенное отображение:

return word_map;

Вот как выглядит вызов этой функции из main():

int main()

{

// считываем файл и выделяем слова

vectorstring, allocator *text_file = retrieve_text();

text_loc *text_locations = separate_words( text_file );

// обработаем слова

// ...

// построим отображение слов на векторы позиций

mapstring,lос*,lessstring,allocator

*text_map = build_word_map( text_locatons );

// ...

}

6.12.2. Поиск и извлечение элемента отображения

Оператор взятия индекса является простейшим способом извлечения элемента. Например:

// mapstring,int word_count;

int count = word_count[ "wrinkles" ];

Однако этот способ работает так, как надо, только при условии, что запрашиваемый ключ действительно содержится в отображении. Иначе оператор взятия индекса поместит в отображение элемент с таким ключом. В данном случае в word_count занесется пара

string( "wrinkles" ), 0

Класс map предоставляет две операции для того, чтобы выяснить, содержится ли в нем определенное значение ключа.

count(keyValue): функция-член count() возвращает количество элементов с данным ключом. (Для отображения оно равно только 0 или 1). Если count() вернула 1, мы можем смело использовать индексацию:

int count = 0;

if ( word_count.count( "wrinkles" ))

count = word_count[ "wrinkles" ];

*

find(keyValue): функция-член find() возвращает итератор, указывающий на элемент, если ключ найден, и итератор end() в противном случае. Например:

int count = 0;

mapstring,int::iterator it = word_count.find( "wrinkles" );

if ( it != word_count.end() )

count = (*it).second;

*

Значением итератора является указатель на объект pair, в котором first содержит ключ, а second – значение. (Мы вернемся к этому в следующем подразделе.)

6.12.3. Навигация по элементам отображения

После того как мы построили отображение, хотелось бы распечатать его содержимое. Мы можем сделать это, используя итератор, начальное и конечное значение которого получают с помощью функций-членов begin() и end(). Вот текст функции display_map_text():

void

display_map_text( mapstring,loc* *text_map )

{

typedef mapstring,loc* tmap;

tmap::iterator iter = text_map-begin(),

iter_end = text_map-end();

while ( iter != iter_end )

{

cout "word: " (*iter).first " (";

int loc_cnt = 0;

loc *text_locs = (*iter).second;

loc::iterator liter = text_locs-begin(),

liter_end = text_locs-end();

while (liter != liter_end ) {