2015-11-12 2 views
-2

Что меня смущает, так это то, что у меня есть карта, состоящая из size_t строки в качестве ключа, и строки как значение.Как продвигать итератор C++ через каждый символ в строке

std::multimap<size_t, std::string> wordMap; 

Тогда у меня есть пара, которая хранит equal_range для всех строк с размером 4. Затем я хочу, чтобы перебирать в начале этого equal_range до конца этого equal_range. Начало - моя пара. Сначала и конец - моя пара. Вторая. Как бы я перебирал через каждый символ, что моя пара. Сначала указывает, а затем сравнивает это с каждым словом между парами. Первый и пара. Второй?

pair<multimap<size_t, string>::iterator, multimap<size_t, string>::iterator> key_range; 
key_range = wordMap.equal_range(n); 

В принципе, я хочу сравнить каждую букву в слове1 с каждым символом слова2. Продвиньте itr2, который является словом2, к следующему слову и сравните каждую букву в этой букве с каждой буквой в слове 1. Сделайте это для каждого слова, затем переместите itr1, который является словом1, к другому слову и сравните это с каждым словом. Как я могу получить каждый символ, на который указывает itr2? Я думаю, что первый цикл for выполняет это для первого итератора, но я не знаю, как это сделать для itr2.

for (word_map::iterator itr = key_range.first; itr != key_range.second; itr++) { //this loop will iterate through every word to be compared 
for (word_map::iterator itr2 = next(key_range.first); itr2 != key_range.second; itr2++) { //this loop will iterate through every word being compared against itr1 
int i = 0; 
int hit = 0; 
for (char& c1 : itr->first) { 
      char& c2{ (itr2)->first[i] }; 
    if(c1 != c2) 
    hit++; 
i++; 
} 
} 

Я хотел бы сравнить каждую букву в каждом слове друг против друга, пока они имеют одинаковый размер строки. Тогда, если hit == 1 означает, что слова отключены только на 1 символ, и они должны быть отображены или сохранены в контейнере STL определенного типа, который группирует их. Я все еще новичок в STL, поэтому я думаю о наборе, но мне нужно больше узнать об этом.

+0

для (word_map :: итератор itr2 = * (key_range ++). Первое, что я попытался – user5544610

+0

Вы можете использовать 'станд :: следующая (key_range.first)', чтобы получить итератор после того. Он выиграл» t, если предоставленный итератор находится в конце. –

+0

Итак, вы в основном хотите сравнить первое слово (на которое указывает key_range.first) на каждое другое слово (т.е. на каждый последующий итератор)? – notmyfriend

ответ

1

Во-первых, у вас будет больше шансов получить помощь, если вы предоставили минимальный компилируемый пример. Я принимаю ваши слова std::string s за этот ответ, но вы знаете, что они говорят о допущении.

Есть такие алгоритмы, как «zip», который реализован в Boost специально для итерации над коллекциями mulitple одновременно, но я не думаю, что в стандартной библиотеке что-то сравнимо.

Простым, но неприятно неудобным подходом было бы просто вручную перебирать обе строки. Это будет выводить каждую букву в двух словах до тех пор, пока не закончится одно слово или не будет различий.

Обратите внимание на все мелкие биты: вы должны убедиться, что оба итератора действительны во все времена, если одно слово заканчивается перед другим, и разработка того, что на самом деле произошло, немного громоздка.

#include <string> 
#include <iostream> 

int main() 
{ 
    std::string word1 = "capsicum"; 
    std::string word2 = "capsicube"; 

    std::string::iterator it1 = word1.begin(); 
    std::string::iterator it2 = word2.begin(); 

    while (it1 != word1.end() && it2 != word2.end()) 
    { 
      // characters are different! 
      if (*it1 != *it2) 
        break; 

      // characters are the same 
      std::cout << "Both have: " << *it1 << std::endl; 

      // advance both iterators 
      ++it1; 
      ++it2; 
    } 

    if (it1 == word1.end() && it2 == word2.end()) 
    { 
      std::cout << "Words were the same!" << std::endl; 
    } 
    else if (it1 == word1.end()) 
    { 
      std::cout << "Word 1 was shorter than word 2." << std::endl; 
    } 
    else if (it2 == word2.end()) 
    { 
      std::cout << "Word 1 was longer than word 2." << std::endl; 
    } 
    else 
    { 
      std::cout << "Words were different after position " << (it1 - word1.begin()) 
         << ": '" << *it1 << "' vs '" << *it2 << "'" << std::endl; 
    } 
} 
+0

Спасибо, что помогает. Но меня смущает то, что у меня есть карта, состоящая из size_t строки в качестве ключа, и строки как значение. Затем у меня есть пара, которая хранит equal_range для всех строк с размером 4. Затем я хочу итерации через начало этого equal_range до конца этого equal_range. Начало - моя пара. Сначала и конец - моя пара. Вторая. Как бы я перебирал через каждый символ, что моя пара. Сначала указывает, а затем сравнивает это с каждым словом между парами. Первый и пара. Второй? – user5544610

+0

@ user5544610 - можете ли вы обновить свой вопрос, включив эту дополнительную информацию, желательно в виде простого, но действительного кода? – notmyfriend

+0

Хорошо, я обновил свой оригинальный вопрос и предоставил весь код, который я написал. – user5544610

0

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

Я написал это как minimal, complete, verifiable example, что идеально, как вы должны задавать свои вопросы. Я также использовал возможности C++ 11 для краткости/удобочитаемости.

Надеемся, что встроенные комментарии объяснят вам все, что вам нужно, по крайней мере, сделать свое собственное исследование за все, что вы не полностью понимаете, но не стесняйтесь комментировать, если у вас есть еще вопросы. Основная идея состоит в том, чтобы сохранить первое слово (с использованием итератора key_range.first), а затем начать итерацию с после итератора с использованием std::next(), пока мы не доберемся до конца итератора в key_pair.second.

Это дает нам word1 вне цикла и word2 в пределах цикла, который будет установлен на каждое другое слово в списке. Затем мы используем метод «двойного вмешательства», который я опубликовал в своем другом ответе, чтобы сравнить каждый символ слова по характеру.

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

int 
main() 
{ 
    std::multimap<size_t, std::string> wordMap; 

    wordMap.insert({4, "dogs"}); 
    wordMap.insert({4, "digs"}); 
    wordMap.insert({4, "does"}); 
    wordMap.insert({4, "dogs"}); 
    wordMap.insert({4, "dibs"}); 

    // original type declaration... 
    // std::pair<std::multimap<size_t, std::string>::iterator, std::multimap<size_t, std::string>::iterator> key_range; 

    // C++11 type inference... 
    auto key_range = wordMap.equal_range(4); 

    // make sure the range wasn't empty 
    if (key_range.first == key_range.second) 
    { 
      std::cerr << "No words in desired range." << std::endl; 
      return 1; 
    } 

    // get a reference to the first word 
    std::string const& word1 = key_range.first->second; 


    std::cout << "Comparing '" << word1 << "' to..." << std::endl; 

    // loop through every iterator from the key_range, skipping for the first 
    // (since that's the word we're comparing everything else to) 
    for (auto itr = std::next(key_range.first); itr != key_range.second; ++itr) 
    { 
      // create a reference for clarity 
      std::string const& word2 = itr->second; 

      std::cout << "... '" << word2 << "'"; 

      // hit counter; where hit is defined as characters not matching 
      int hit = 0; 

      // get iterators to the start of each word 
      auto witr1 = word1.begin(); 
      auto witr2 = word2.begin(); 

      // loop until we reach the end of either iterator. If we're completely 
      // confident the two words are the same length, we could only check 
      // one of them; but defensive coding is a good idea. 
      while (witr1 != word1.end() && witr2 != word2.end()) 
      { 
        // dereferencing the iterators will yield a char; so compare them 
        if (*witr1 != *witr2) 
          ++hit; 

        // advance both iterators 
        ++witr1; 
        ++witr2; 
      } 

      // do something depending on the number of hits 
      if (hit <= 1) 
      { 
        std::cout << " ... close enough!" << std::endl; 
      } 
      else 
      { 
        std::cout << " ... not a match, " << hit << " hits." << std::endl; 
      } 
    } 
} 
+0

Красивый ответ: D – user5544610

+0

auto witr1 = word1.begin(); будет ли это строковым итератором? Просто для разъяснения. – user5544610

+0

@ user5544610 - да, это должно быть эквивалентно 'std :: string :: const_iterator witr1 = word1.begin();' – notmyfriend

Смежные вопросы