2012-10-20 3 views
5

Ich möchte wissen, wie ich die Indexpositionen von Elementen finden können, die eine bestimmte Bedingung (z. B. größer als) überprüfen. Zum Beispiel, wenn ich ein Vektor von int haben WerteErhalten Sie alle Positionen von Elementen in STL-Vektor, die größer als ein Wert sind

vector<int> V; 

V die Werte 3 2 5 8 2 1 10 4 7

enthält, und ich möchte alle Indexpositionen von Elementen erhalten, die größer sind als 5. Ich weiß std::find_if aber Laut der Dokumentation findet es nur das erste Element, das eine Bedingung erfüllt.

+2

Sie können 'std :: find_if' in einer Schleife, Speicherpositionen wie Sie gehen. – chris

+1

verwenden Sie es wiederholt, beginnend nicht von Anfang an, sondern von wo Sie gerade gefunden haben. –

+0

@oldrinb Eigentlich muss ich die Positionen holen, denn dann muss ich Elemente von einem anderen Vektor an den gleichen Positionen holen. – saloua

Antwort

8

Loop std::find_if, beginnend von wo Sie zuletzt gestoppt haben.

Probe (see it work):

std::vector<size_t> results; 

auto it = std::find_if(std::begin(v), std::end(v), [](int i){return i > 5;}); 
while (it != std::end(v)) { 
    results.emplace_back(std::distance(std::begin(v), it)); 
    it = std::find_if(std::next(it), std::end(v), [](int i){return i > 5;}); 
} 

Zuerst setzen wir den Iterator mit dem ersten Ergebnis auf. Wenn es nicht gefunden wird, wird die while-Schleife nie ausgeführt. Andernfalls wird die Indexposition gespeichert (std::distance ist im Grunde eine allgemeinere it - std::begin(v)) und die Suche wird fortgesetzt.

+0

+1 für 'std :: next' –

8

Ich glaube, ich std::copy_if verwenden würde:

std::vector<int> x{3, 2, 5, 8, 2, 1, 10, 4, 7}; 
std::vector<size_t> y(x.size()); 

std::iota(y.begin(), y.end(), 0); 
std::copy_if(y.begin(), y.end(), 
      std::ostream_iterator<size_t>(std::cout, " "), 
      [=](size_t i) { return x[i] > 5; }); 

Für mich ergibt dies 3 6 8, die Indizes von 8, 10 und 7 in x - genau das, was wir wollen.

Wenn Sie mit einem C++ 98/03-Compiler/Bibliothek stecken, verwenden Sie stattdessen std::remove_copy_if (und umgekehrt den Sinn des Vergleichs). In diesem Fall können Sie natürlich auch keinen Lambda für den Vergleich verwenden.

+0

Ich mag es. Guter Gedanke. – chris

+2

+1 für 'std :: iota' –

1

Just for fun, transform_if Algorithmus:

#include <vector> 
#include <iterator> 
#include <algorithm> 
#include <iostream> 

template<typename InputIterator, typename OutputIterator, 
    typename UnaryPredicate, typename UnaryFunction> 
OutputIterator 
transform_if (InputIterator first, InputIterator last, 
    OutputIterator result, UnaryPredicate pred, 
    UnaryFunction func) 
{ 
    for (; first != last; ++first, ++result) 
     if (pred(*first)) 
      *result = func(*first); 
    return result; 
} 

int main() 
{ 
    std::vector<int> x {3, 2, 5, 8, 2, 1, 10, 4, 7}; 
    std::vector<size_t> indices; 

    size_t index = 0; 
    transform_if(x.begin(), x.end(), std::back_inserter(indices), 
     [&](int i){ return ++index, i > 5; }, 
     [&](int){ return index-1; }); 

    std::copy(indices.begin(), indices.end(), 
       std::ostream_iterator<size_t>(std::cout, " ")); 
} 

Ausgang: 3 6 8

Verwandte Themen