2015-06-17 2 views
3

Хотелось бы итерации по карте, но внутренний цикл просто переходил бы через верхнюю часть элементов. с вектором это будет выглядеть так:C++: двойная итерация по карте

for(auto element1 = myVector.begin() ; element1 != myVector.end() ; ++element1){ 
    for(auto element2 = element1 + 1; element2 != myVector.end() ; ++element2){ 
     //my stuff 
    } 
} 

Но с картой element1 + 1 возвращает ошибку no operator matches this operand .. Я считаю, что исходит из того, что элемент не заказанные на карте.

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

for(auto element1 = myMap.begin() ; element1 != myMap.end() ; ++element1){ 
    for(auto element2 = element1; element2 != myMap.end() ; ++element2){ 
     if(element->first != element2->first) 
     //my stuff 
    } 
} 
+0

@Pixelchemist: Правильно, я не могу читать –

+0

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

ответ

7

Вы можете использовать std::next сделать это:

for(auto element1 = myMap.begin() ; element1 != myMap.end() ; ++element1) { 
    for(auto element2 = std::next(element1) ; element2 != myMap.end() ; ++element2) { 
     //my stuff 
    } 
} 

Вот дополнительная справочная информация о std::next. std::next имеет необязательный второй аргумент, который представляет собой число элементов, которые следует за переданным итератором. Например, std::next(element1, 2) вернет итератор для второго элемента после element1. Как указано в комментариях, вы должны должны быть осторожны при использовании std::next, особенно в петлях. Если it указывает на элемент до myMap.end(), то использование std::next(it, 2) приводит к неопределенному поведению. Вы хотите убедиться, что использование этого никогда не пройдет конец контейнера.

Вы можете думать о std::next, как если бы она была реализована следующим образом:

// If distance is negative, then i must meet the requirements of BidirectionalIterator 
// Otherwise, i must meet the requirements of ForwardIterator. 
template<class ForwardIterator> 
ForwardIterator next(ForwardInterator i, int distance) { 
    for(; distance < 0 ; ++distance) { 
     --i; 
    } 
    for(; distance > 0 ; --distance) { 
     ++i; 
    } 

    return i; 
} 

который может быть эквивалентно реализована следующим образом:

template<class ForwardIterator> 
ForwardIterator next(ForwardIterator i, int distance) { 
    std::advance(i, distance); 
    return i; 
} 
+0

'std :: next (element1, 2)' не может быть использован здесь – Slava

+0

@Slava Почему бы и нет? Меня устраивает. – Daniel

+0

@ СЛАВА Почему? 'next()' принимает форвардный итератор, а карта имеет двунаправленный итератор. – NathanOliver

0

Простейшее решение было бы пропустить первый один:

for(auto element1 = myMap.begin() ; element1 != myMap.end() ; ++element1){ 
    for(auto element2 = element1; element2 != myMap.end() ; ++element2){ 
     if(element2 == element1) continue; 
     //my stuff 
    } 
} 
+1

Второй фрагмент перемещает элемент 'element1', который не предназначен. – timrau

+0

@timrau он перемещает элемент1 вместо этого в первом 'for' – Slava

+0

Но 1-й элемент просто пропущен обоими итераторами – timrau

0

Даже если вы не знаете о некоторых из более новые объекты на C++, такие как std::next() (что является хорошим способом решения этой проблемы), это, как представляется, является довольно сложной задачей:

for(auto element1 = myMap.begin() ; element1 != myMap.end() ; ++element1){ 
    auto element2 = element1; 
    ++element2; 
    for(; element2 != myMap.end() ; ++element2){ 
     //my stuff 
    } 
} 
Смежные вопросы