2014-12-13 2 views
6

Мне было интересно, есть ли какой-либо встроенный или хорошо установленный способ (то есть через лямбда), чтобы пройти через элементы std :: list и найти все те, которые соответствуют данное значение? Я знаю, что могу перебирать все из них, но я подумал, что спрошу, есть ли способ получить итератор, который выполняет только те элементы, которые соответствуют заданным критериям? Мой пример ниже дает мне только итератор для первого элемента соответствия.Найти все совпадающие элементы в std :: list

#include <list> 
#include <algorithm> 
#include <stdio.h> 

int main() 
{ 
    std::list<int> List; 
    List.push_back(100); 
    List.push_back(200); 
    List.push_back(300); 
    List.push_back(100); 
    int findValue = 100; 

    auto it = std::find_if(List.begin(), List.end(), [findValue](const int value) 
    { 
     return (value == findValue); 
    }); 

    if (it != List.end()) 
    { 
     for (; it != List.end(); ++it) 
     { 
      printf("%d\n", * it); 
     } 
    } 
    return 0; 
} 

Благодарим за любую отзыв.

+0

Неоднократно вызывайте 'find_if', чтобы найти оставшиеся совпадения, просто увеличивайте начальный итератор до каждого вызова (при условии, что последний вызов привел к совпадению). Если вы делаете это достаточно часто, напишите функцию. И если все, что вы делаете, использует 'operator ==' внутри предиката, нет необходимости в 'find_if',' find' делает это для вас. – Praetorian

+6

* «если есть способ получить итератор, который выполняет итерации только с элементами, которые соответствуют заданным критериям». Возможно, [Итераторы фильтра] (http://www.boost.org/doc/libs/1_57_0/libs/iterator/ док/filter_iterator.html)? – dyp

ответ

7

std::find_if является обобщением std::find, если вам нужна функция для проверки элементов, которые вы хотите, а не простой тест на равенство. Если вы просто хотите сделать простой тест на равенство, тогда нет необходимости в обобщенной форме, и лямбда просто добавит сложности и многословия. Просто используйте std::find(begin, end, findValue) вместо:

std::vector<std::list<int>::const_iterator> matches; 
auto i = list.begin(), end = list.end(); 
while (i != end) 
{ 
    i = std::find(i, end, findValue); 
    if (i != end) 
    matches.push_back(i++); 
} 

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

std::vector<std::list<int>::const_iterator> matches; 
for (auto i = list.begin(), toofar = l.end(); i != toofar; ++i) 
    if (*i == findValue) 
    matches.push_back(i); 
7

Использование copy_if и iterators:

#include <list> 
#include <algorithm> 
#include <iterator> 
#include <iostream> 

int main() 
{ 
    std::list<int> List; 
    List.push_back(100); 
    List.push_back(200); 
    List.push_back(300); 
    List.push_back(100); 
    int findValue = 100; 

    std::copy_if(List.begin(), List.end(), std::ostream_iterator<int>(std::cout, "\n"), [&](int v) { 
     return v == findValue; 
    }); 
    return 0; 
} 

Если вы не хотят напрямую выводить результаты и хотите заполнить другой контейнер совпадениями:

std::vector<int> matches; 
std::copy_if(List.begin(), List.end(), std::back_inserter(matches), [&](int v) { 
    return v == findValue; 
}); 
9

boost::filter_iterator позволяет работать только с элементами итерации, которые удовлетворяют предикату. Учитывая предикат Pred и контейнер Cont,

auto begin_iter = boost::make_filter_iterator(Pred, std::begin(Cont), std::end(Cont)); 
auto end_iter = boost::make_filter_iterator(Pred, std::end(Cont), std::end(Cont)); 

Теперь вы можете использовать begin_iter и end_iter, как если бы они были начинаются и заканчиваются итераторы из контейнера, содержащего только те элементы Cont, удовлетворяющие Pred. Другим дополнительным преимуществом является то, что вы можете обернуть итераторы в boost::iterator_range и использовать его в тех местах, которые ожидают на итерацию объект, как диапазон на основе for цикла, как это:

auto range = boost::make_iterator_range(begin_iter, end_iter); 
for(auto x : range) do_something(x); 

В частности, установка Pred к функтора (может быть лямбда), который проверяет равенство с вашим фиксированным значением, предоставит вам итераторы, которые вам нужны.

+0

Это лучший ответ! – PeterT

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