Пропустить первую итерацию по unordered_map

В цикле for с auto итератор перебирает unordered_map. Как это:

using RuleIndex = std::unordered_map<uint, Symbol*>;
RuleIndex rule_index;
for(const auto & rule_pair : rule_index ) {
   std::cout << rule_pair.first << ": ";
   printList(rule_pair.second, 0);
   std::cout << std::endl;
}

Предположим, что все переменные определены правильно, так как код работает нормально. Мой вопрос, как я могу исключить первую итерацию? Например, карта содержит 3 строки, и текущий цикл повторяется для 0, 1, 2. Я хочу перебирать только 1 и 2.


person mahmood    schedule 12.05.2015    source источник
comment
auto it = rule_index.begin(); /* or cbegin() */ it++; while (it != rule_index.end()) { /* ... */ it++; } или что-то подобное.   -  person Biffen    schedule 12.05.2015
comment
Интересный один лайнер   -  person mahmood    schedule 12.05.2015
comment
Это больше похоже на 6 строк...   -  person Biffen    schedule 12.05.2015
comment
@Biffen, который попытается продвинуть итератор дальше конца, если коллекция пуста   -  person mtijn    schedule 12.05.2015
comment
@mtijn Хороший улов, it++ можно заменить на if (it != rule_index.end()) it++;   -  person Biffen    schedule 12.05.2015
comment
Вы уверены, что пропуск первой строки всегда является лучшим решением? unordered_map может измениться порядок хранимых пар.   -  person awesoon    schedule 12.05.2015
comment
@soon: Да, но я думаю, что первая строка (правило) всегда есть в соответствии с кодом. При каких обстоятельствах порядок может измениться?   -  person mahmood    schedule 12.05.2015
comment
Это определяется реализацией. Он может хранить порядок для вашей конфигурации, но не для других. Просто взгляните на пример (coliru): порядок кажется обратным.   -  person awesoon    schedule 12.05.2015
comment
Скоро полностью прав: порядок элементов зависит от их хэш-значения, от того, как оно отображается в текущее количество сегментов, и от порядка вставки; даже если два unordered_set в настоящее время имеют одни и те же элементы, которые были добавлены в одном и том же порядке, разные более ранние события, включая, помимо прочего, reserve и ручные или автоматические вызовы resize, могут привести к совершенно другому порядку итераций.   -  person Tony Delroy    schedule 14.05.2015
comment
Да, подождите, это плохой вопрос. Название полностью не отражает то, о чем спрашивают... и все, что связано с unordered_map, не должно зависеть от порядка - это буквально в названии структуры данных.   -  person Alex Ryan    schedule 07.12.2015


Ответы (3)


bool is_first_iteration = true;
for(const auto & rule_pair : rule_index) {
   if (std::exchange(is_first_iteration, false)) continue;
   std::cout << rule_pair.first << ": ";
   printList(rule_pair.second, 0);
   std::cout << std::endl;
}

Вызов std::exchange присваивает false значению is_first_iteration и возвращает предыдущее значение. На самом деле это один из вариантов использования, обсуждаемых в документ, предлагающий std::exchange для C++14. В этом документе также показана эталонная реализация, которую вы можете использовать, если вы застряли на C++11.

person T.C.    schedule 12.05.2015
comment
Очень хорошее решение с умным использованием STL! - person Yury Bayda; 12.05.2015

Если вы не можете использовать std::exchange (из-за ограничения С++ 11), это простое решение также может работать:

bool is_first_iteration = true;
for (const auto & rule_pair : rule_index) 
{
  if (is_first_iteration) 
  {
    is_first_iteration = false;
    continue;
  }
  std::cout << rule_pair.first << ": ";
  printList(rule_pair.second, 0);
  std::cout << std::endl;
}
person Keplerian    schedule 12.05.2015

Краткий вариант C++11, который я иногда использую, который также содержит иногда удобный счетчик. Я показал if (i++) ниже, который зависит от преобразования 0 в false, в то время как другие числа преобразуются в true, но вы можете поставить if (++i > 1), если вам так удобнее:

size_t i = 0;
for (const auto & rule_pair : rule_index)
    if (i++)
    {
        ...
    }

...или if (++i == 1) continue;... если хотите...

Несмотря на то, что они просты в написании, лаконичны и иногда полезны, они могут быть менее поддающимися оптимизации, чем логическая версия - оцените, если вам небезразлично.


Еще один подход, который иногда полезен:

for (const auto & rule_pair : rule_index)
    if (&rule_pair != &*std::begin(rule_index))
    {
        ...
    }
person Tony Delroy    schedule 14.05.2015