2014-12-13 9 views
6

Ich frage mich, ob es einen eingebauten oder gut etablierten Weg (zB via Lambda) gibt, um durch die Elemente einer std :: list zu gehen und alle zu finden, die zu a passen gegebener Wert? Ich weiß, dass ich alle durchlaufen kann, aber ich dachte, ich würde fragen, ob es einen Weg gibt, einen Iterator zu bekommen, der nur durch die Elemente iteriert, die bestimmten Kriterien entsprechen? Mein Beispiel unten gibt nur den Iterator für das erste übereinstimmende Element.Finden Sie alle passenden Elemente in 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; 
} 

Danke für jede Rückmeldung.

+0

Rufen Sie wiederholt 'find_if' an, um die verbleibenden Übereinstimmungen zu finden. Erhöhen Sie den Begin-Iterator vor jedem Aufruf (vorausgesetzt, der letzte Aufruf führte zu einer Übereinstimmung). Wenn Sie dies oft genug tun, schreiben Sie eine Funktion. Und wenn Sie nur 'operator ==' innerhalb des Prädikats verwenden, brauchen Sie 'find_if' nicht,' find' macht das für Sie. – Praetorian

+6

* "Wenn es einen Weg gibt, einen Iterator zu bekommen, der nur die Elemente durchläuft, die einem bestimmten Kriterium entsprechen" * Vielleicht [Filter Iteratoren] (http://www.boost.org/doc/libs/1_57_0/libs/iterator/ doc/filter_iterator.html)? – dyp

Antwort

7

std::find_if ist eine Verallgemeinerung von std::find für wenn Sie eine Funktion benötigen, um nach den Elementen zu suchen, die Sie wünschen, anstatt einen einfachen Test auf Gleichheit. Wenn Sie nur einen einfachen Test auf Gleichheit durchführen wollen, dann brauchen Sie das verallgemeinerte Formular nicht, und das Lambda fügt einfach Komplexität und Ausführlichkeit hinzu. Verwenden Sie einfach std::find(begin, end, findValue) statt:

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++); 
} 

Aber anstatt find in einer Schleife aufrufen würde ich nur die Schleife schreiben manuell:

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

Mit copy_if und 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; 
} 

Wenn Sie möchte die Ergebnisse nicht direkt ausgeben und möchte einen anderen Container mit den Übereinstimmungen füllen:

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

boost::filter_iterator können Sie nur mit den Elementen eines iterable arbeiten, die ein Prädikat erfüllen. Bei einem Prädikat Pred und einen Behälter 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)); 

Sie jetzt begin_iter verwenden können und end_iter als ob sie die beginnen waren und am Ende Iteratoren eines Behälters nur die Elemente von Cont enthält, die Pred zufrieden. Ein weiterer zusätzlicher Vorteil ist, dass Sie die Iteratoren in einer boost::iterator_range wickeln können und es an Orten, die eine iterable Objekt erwarten, wie eine bereichsbasierte for Schleife wie folgt aus:

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

Insbesondere Pred zu einem Funktor Einstellung (könnte ein Lambda sein), das auf Gleichheit mit Ihrem festen Wert prüft, gibt Ihnen die Iteratoren, die Sie benötigen.

+0

Dies ist die beste Antwort! – PeterT

Verwandte Themen