nach wert im stl vector suchen und position zurück bekommen



  • Hi,

    ich habe einen

    vector<string>
    

    dieser ist mit Daten gefüllt. Nun möchte ich einen string daraus suchen(find())
    und mir die Position zurückgeben lassen wo dieser String im vector gefunden wurde.

    Wie mache ich das?

    Dank und Gruß



  • Mit einer for-Schleife (die Position im vector ist dann doch einfach deine Zählvariable, die du als vector-Index benutzt)?


  • Administrator

    http://www.cplusplus.com/reference/algorithm/find/
    (Wie du an die Iteratoren kommst, weisst du hoffentlich ...)

    Grüssli



  • @Dravere: Ja da bekomme ich ja nur den Wert des vectors. Ich möchte aber die Position haben an der dieser Wert im vector sitzt.

    @_matze: schon klar, bin aber davon ausgegangen das es eine Funktion in der STL gibt, die mir den Index zurückgeben kann an welcher Position mein gesuchter Wert sitzt. Deshalb fragte ich ja um keine Schleife benutzen zu müssen.





  • Entweder wie vorgeschlagen std::distance() , oder – da der Container std::vector mit Random-Access-Iteratoren arbeitet – ist auch operator- möglich. Du musst allerdings immer prüfen, ob überhaupt was gefunden wurde, sonst hast du einen ungültigen Index.

    std::vector<std::string> vec;
    // ...
    size_t index = std::find(vec.begin(), vec.end(), str) - vec.begin();
    

    Oder du schreibst dir gleich selbst einen Algorithmus...



  • @blubb: Über Distance funzt es. Danke



  • Hallo alle zusammen!
    Ich habe ein ähnliches Problem wie oben beschrieben.
    Ich habe eine Struktur angelegt mit insges. 6 Strings. Und dann einen Vektor, der vom Typ dieser Struktur ist und Elemente davon enthält.

    struct  CONNECTION{
    		std::string source;
    		std::string src_home;
    		std::string target;
    		std::string tar_home;
    		std::string patching_group;
    		std::string SigString;
    	};				    
    
    std::vector<CONNECTION> connection_vector; //vector of type CONNECTION
    

    Nun möchte ich in einer Funktion

    int InfoClass::findConnectionString(std::string formated_con_string)
    

    den übergebenen String "formated_con_string" im Vektor "connection_vector" finden. Der gesuchte String steht in der Struktur immer im Element "SigString". Wenn ich den "formated_con_string" gefunden habe, möchte ich die restlichen, zu diesem String gehörigen Strukturelemente herausgreifen können.

    Es wäre nett und richtig klasse, wenn ihr mir weiterhelfen könntet.
    Danke schon mal im Voraus!



  • Siehe std::find_if



  • Danke Krümelkacker.
    Hm, ich habe es nun folgendermaßen probiert:

    int InfoClass::findConnectionString(std::string formated_con_string)
    {
    	std::vector<CONNECTION>::iterator test;
    	test = std::find_if (connection_vector.begin(), connection_vector.end(), formated_con_string);
    	return test;
    }
    

    Erhalte dann aber folgende Fehlermeldung:
    "error C2440: 'return' : cannot convert from 'struct InfoClass::CONNECTION *' to 'int' "
    Das sieht mir prinzipiell nach einem Fehler aus, den man beheben kann... aber wie? Was liefert mit std::find_if für einen Rückgabewert? Ich war auf dieser Seite, wurde daraus aber nicht so richtig schlau: http://www.cplusplus.com/reference/algorithm/find_if/

    Und falls find_if tatsächlich meinen String in den Strukturen, die der Vektor enthält, findet, wie greife ich dann auf die restlichen Elemente der gefundenen Struktur zu?



  • Ich war auf dieser Seite, wurde daraus aber nicht so richtig schlau

    Was ist denn unklar?



  • Zum Beispiel, was es mit diesem "pred" auf sich hat... irwie hängt das ja mit dem Rückgabewert von find_if zusammen. Bekommt man da nur einen BOOL-Wert zurück? Oder kann ich mit dem Rückgabewert dann wirklich auf die Elemente der gefundenen Struktur zugreifen?
    Ich steh da irgendwie auf dem Schlauch und die Fehlermeldung habe ich auch noch nicht weg bekommen... mach da jetzt schon ewig rum und habs acuh schon mit "find" probiert und mit for-Schleifen... irgendwie bekomme ich immer Fehlermeldungen, dass der Type nicht passt eines Übergabewertes oder ähnliches.



  • Also ich habe da immer eine eigene 10-Zeilen Funktion geschrieben, ca. so:

    int GetIndex( CString name )
    {
        int size = IrgendeinVektor.size();
        for( int i = 0; i < size; i++ )
        {
            if( IrgendeinVektor[i] == name )
                return i;
        }
    
        return -1;
    }
    

    Wobei -1 zurückgegeben wird wenn "name" nicht gefunden wird. Halte ich für die einfachste Lösung, und ich wüsste nicht warum die anderen (viel) schneller sein sollten.



  • std::find_if() gibt einen Iterator zurück. Dieser zeigt auf das erste gefundene Element – oder auf das Ende der übergebenen Range, wenn nichts gefunden wurde.

    typedef std::vector<MyClass> Container;
    Container c;
    // ...
    Container::iterator itr = std::find_if(c.begin(), c.end(), pred);
    
    if (itr == c.end())
    {
        // nichts gefunden
    }
    else
    {
        // Der Index berechnet sich so:
        size_t index = itr - c.begin();
    }
    

    Aber oft will man gar nicht in Indizes umrechnen.



  • Stoph schrieb:

    Zum Beispiel, was es mit diesem "pred" auf sich hat...

    ...steht für "predicate", zu Deutsch: "Prädikat". Das ist ein Funktionsobjekt, welches die Argumente (und sich selbst normalerweise auch) bei einem Aufruf nicht verändert und einen Wahrheitswert zurückliefert. ZB so:

    struct mypred {
      bool operator()(CONNECTION const& c) const {
        return c.SigString == "123";
      }
    };
    

    Damit sagst Du find_if, welches Element Du haben willst.



  • Hey super! Vielen Dank an euch alle für die Hilfe! Ich habe es im Endeffekt jetzt so gemacht, wie RedPuma vorgeschlagen hatte. Hatte erst eine Lösung so ähnlich wie Nexus vorgeschlagen hat, aber mir hat die entscheidende Zeile gefehlt, wie ich dann auf den Index zugreifen kann! Vielen Dank Nexus! Jetzt weiß ich, wie das geht! Das Problem, das ich vorhin beschrieben hatte mit dem Fehler bzgl Rückgabetyp hat sich auch geklärt... ich hätte als Rückgabetyp nicht "int" sondern

    std::vector<CONNECTION>
    

    wählen müssen... dummer Fehler 🙂
    Hier nun meine Lösung:

    int InfoClass::findConnectionString(std::string formated_con_string)
    {
    	int iFoundVectorPos = -1;
    	for (int vectorPos=0; vectorPos<connection_vector.size(); vectorPos++ ) 
        { 
            if (connection_vector[vectorPos].SigString == formated_con_string) 
    		{
    			iFoundVectorPos = vectorPos;
    			break;
    		}
        } 
    
    	return iFoundVectorPos;
    }
    


  • Übergib doch den String als Referenz auf const , dann sparst du dir eine unnötige Kopie:

    const std::string& formatted_con_string
    

    Übrigens gibt es etliche Möglichkeiten zur Fallunterscheidung bei gefundenen/nicht gefundenen Strings. Elegant finde ich z.B.:

    bool InfoClass::findConnectionString(const std::string& formatted_con_string, size_t& index)
    {
        // falls gefunden, speichere Position in index und gib true zurück
        // sonst gib false zurück
    }
    
    // Anwendung:
    size_t index; // size_t ist ein unsigned-Typ
    if (myInfo.findConnectionString("test", index))
    {
       // arbeite mit index
    }
    

    Vorteil ist unter anderem, dass du eine einheitliche Überladung anbieten kannst, wenn dich nur interessiert, ob ein String gefunden wurde:

    bool InfoClass::findConnectionString(const std::string& formatted_con_string)
    {
        // implementiert mit obiger Funktion
        size_t dummy;
        return findConnectionString(formatted_con_string, dummy);
    }
    
    // Anwendung:
    if (myInfo.findConnectionString("test"))
    {
       // tue etwas
    }
    

    Aber das nur so als Inspiration. Hauptsache, du wirfst keine Exceptions beim Nicht-Finden. 😉


Anmelden zum Antworten