2016-08-06 7 views
8

Ich möchte nach einem Wert in zwei std::vector suchen. Wenn es in einem von ihnen gefunden wurde, möchte ich seinen Iterator zurückgeben. Wenn nicht, möchte ich einen Wert zurückgeben, der anzeigt, dass er nicht gefunden wurde.Prüfen, ob der Iterator keinem Element zugewiesen ist, wenn kein spezifischer Container vorhanden ist

In normalen Situation, wo nur eine std::vector beteiligt ist, würde ich std::vector::end zurückgeben. Was soll ich in dieser Situation tun?

Normale Situation:

auto find_ten=[](const std::vector<int>& v){ 
    return std::find(v.cbegin(),v.cend(),10); 
} 

Meine Situation:

auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){ 
    auto it1=std::find(v1.cbegin(),v1.cend(),10); 
    if(it1==v1.cend()){ 
     auto it2=std::find(v2.cbegin(),v2.cend(),10); 
     if(it2==v2.cend()){ 
      //What should I return here?? 
     } 
     return it2; 
    } 
    return it1; 
} 

Ich möchte etwas zurückgeben, die ich überprüfen kann es später zu wissen, dass die Zahl 10 in keiner gefunden wurde von ihnen.

+0

Ein Iterator ist _never_ "null". –

+1

(Obwohl ein einzelner Iterator Ihnen helfen kann, können Sie mit einem erstaunlich wenig tun.) –

+0

@LightnessRacesinOrbit korrigiert –

Antwort

8

Seit C++ 14 ist es erlaubt Werte initialisierte Iteratoren zu vergleichen, wenn sie der Kategorie ForwardIterator oder stärker entsprechen (siehe [forward.iterators] Absatz 2). Ein Wert initialisiert Iterator ist das Äquivalent eines Null-Zeiger, so können Sie verwenden:

if(it2==v2.cend()){ 
     return std::vector<int>::iterator{}; 
    } 

Und dann kann der Anrufer tun:

std::vector<int>::iterator not_found{}; 
auto find_ten = ... 
if (find_ten != not_found) 
{ 
    ... 
} 
+0

Danke .. es scheint genau das, was ich suche. Aber ich kann C++ 14 noch nicht benutzen. –

+0

In der Praxis wird es wahrscheinlich mit jeder Version von C++ funktionieren (außer in Iterator-Debugging-Modi), der C++ 14 Standard hat es gerade offiziell gemacht –

+0

Ah Das ist großartig dann –

1
auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){ 
    auto it1=std::find(v1.cbegin(),v1.cend(),10); 
    if(it1==v1.cend()){ 
     auto it2=std::find(v2.cbegin(),v2.cend(),10);   
     return it2; // whether it's end or not 
    } 
    return it1; 
} 

bei der Anwendung, einfach testen (rval != v2.end()) (rval ist der zurückgegebene Iterator). Ich weiß, das ist nicht sehr symmetrisch.

ODER

Geben Sie einen boolean als out Parameter

auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2, bool &found){ 
    found = true; // suppose we will find it 

    auto it1=std::find(v1.cbegin(),v1.cend(),10); 
    if(it1==v1.cend()){ 
     auto it2=std::find(v2.cbegin(),v2.cend(),10); 
     found = it2 != v2.end();  // false if not in v1 or in v2 
     return it2; // whether it's end or not 
    } 

    return it1; 
} 
+1

Wirklich? Ist es wohldefiniert, Iteratoren aus verschiedenen Containern zu vergleichen? Meiner Erfahrung nach ist 'for (auto it = contA.begin(), end = contB.end(); it! = End; ++ it)' nicht gut. –

+0

Ich stimme zu, das ist nicht sehr akademisch, daher meine alternative Lösung. –

1

Sie könnten Sie einfach das am weitesten rechts stehende Ende Iterators Vektor, macht diese logischen Sinn:

auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){ 
    auto it1=std::find(v1.cbegin(),v1.cend(),10); 
    if(it1==v1.cend()){ 
     return std::find(v2.cbegin(),v2.cend(),10); 
    } 
    return it1; 
} 

auto it = find_ten(v1, v2); 
if (it == v2.end()) // no luck 

Oder Sie könnten nehmen ein Iterator-Argument:

auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2, std::vector<int>::iterator endit){ 
    auto it1=std::find(v1.cbegin(),v1.cend(),10); 
    if(it1==v1.cend()){ 
     auto it2=std::find(v2.cbegin(),v2.cend(),10); 
     if(it2==v2.cend()){ 
      return endit; 
     } 
     return it2; 
    } 
    return it1; 
} 

Diese beiden, natürlich auf Ihren Anwendungsfall abhängig: Wenn Sie die zurückgegebene Iterator für mehr als nur einen direkten Zugang zu einem Element verwenden werden, werden Sie einen anderen Ansatz berücksichtigen müssen:

- - EDIT ---

Wenn Sie den Iterator über den direkten Zugriff auf das problematische Element hinaus verwenden möchten, können Sie std::reference_wrapper verwenden, damit Sie einen Verweis auf den betreffenden Vektor zurückgeben können (oder Sie könnten einfach einen Zeiger zurückgeben).

#include <vector> 
#include <algorithm> 
#include <functional> 
#include <iostream> 

using find_ten_t = std::pair<std::reference_wrapper<const std::vector<int>>, std::vector<int>::const_iterator>; 

auto find_ten = [](const std::vector<int>& v1, const std::vector<int>& v2) -> find_ten_t { 
    auto it1 = std::find(v1.cbegin(), v1.cend(), 10); 
    if (it1 != v1.cend()) { 
     return std::make_pair(std::ref(v1), it1); 
    } 
    auto it2 = std::find(v2.cbegin(), v2.cend(), 10); 
    return std::make_pair(std::cref(v2), it2); 
}; 

int main() { 
    std::vector<int> v1{ 1, 2, 3 }; 
    std::vector<int> v2{ 3, 4, 10 }; 
    auto r = find_ten(v1, v2); 
    std::cout << "r.first[0] = " << r.first.get()[0] << "\n"; 
} 

Live-Demo: http://ideone.com/cNLJKg

+0

Ja, es wäre eine schöne schnelle Lösung Danke –

+0

@HumamHelfawi Wenn Sie mehr als direkten Zugriff benötigen, finden Sie unter Bearbeiten. – kfsone

1

Nicht wirklich brillant, nehme ich an, aber ... Ich schlage ein std::pair zurückkehren, wo das erste Element ein int ist (0 für "nicht gefunden", 1 für „gefunden in der ersten "und 2 für" in der zweiten gefunden ") und die zweite ist der Iterator.

So etwas wie

auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){ 
    auto it1=std::find(v1.cbegin(),v1.cend(),10); 
    if(it1==v1.cend()){ 
     auto it2=std::find(v2.cbegin(),v2.cend(),10); 
     if(it2==v2.cend()){ 
      return std::make_pair(0, v1.cend()); // or make_pair(0, v2.cend()) 
     } 
     return std::make_pair(2, it2); 
    } 
    return std::make_pair(1, it1); 
}; 

Oder besser: Sie könnten ein Paar Iterator zurück, wo der zweite die cend() des entsprechenden Vektors ist; so etwas wie

auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){ 
    auto it1=std::find(v1.cbegin(),v1.cend(),10); 
    if(it1==v1.cend()){ 
     return std::make_pair(std::find(v2.cbegin(),v2.cend(),10), v2.cend()); 
    } 
    return std::make_pair(it1, v1.cend()); 
}; 

Ich denke, es ist wichtig, die cend() correspindig Iterator zurück, weil ich glaube, der Iterator zeigt auf 10 verwenden möchten, und man konnte es laufen.

obvioulsy, Wenn Sie wissen nur interessiert sind, wenn 10 in v1 oder in v2 ist, ich nehme an, Sie sollten eine bool Rückkehr: false sonst true für "gefunden",; etwas wie

auto find_ten=[](const std::vector<int>& v1,const std::vector<int>& v2){ 
    auto ret = v1.cend() != std::find(v1.cbegin(),v1.cend(),10); 
    if (ret == false) 
     ret = v2.cend() != std::find(v2.cbegin(),v2.cend(),10); 
    return ret; 
}; 

ps .: Entschuldigung für mein schlechtes Englisch.

+0

@ Jarod42 - Ich stelle mir vor, dass die Verwendung 'std :: option' kann eine Lösung sein, aber ... kann mein Limit sein ... Ich verstehe nicht die Nützlichkeit der Rückgabe eines Const-Iterator ohne Informationen über den Container, der ist verwiesen. – max66

+0

@ Jarod42 - niemand ist perfekt :-) – max66

Verwandte Themen