Oskar
Oskar

Reputation: 65

Find a substring from a vector using iterators

I am trying to make a search function in my application. If the user inputs a substring (or the complete string) I want to know if that substring matches any of the strings or part of the strings stored in my vector.

The following code is written so far:

cout << "Input word to search for: ";
cin >> searchString;


for (multimap <string, vector<string> >::const_iterator it = contactInformationMultimap.cbegin();       it != contactInformationMultimap.cend(); ++it)
{
    for (vector<string>::const_iterator iter = it->second.cbegin(); iter != it->second.cend(); ++iter)
    {
        if (*iter.find(searchString))
            ^^^^^^^^^^^^^^^^^^^^^^^   this does not work, if i cout *iter it is the correct word                     stored in the vector. The problem is that i can not use the find function.
    }                                 
}

Anyone having any suggestions?

Upvotes: 2

Views: 3098

Answers (3)

Ali Akber
Ali Akber

Reputation: 3800

You can use : if ( *iter.find(searchString) != string::npos )

Upvotes: 0

Jerry Coffin
Jerry Coffin

Reputation: 490148

The comments have shown how to correct the syntax so your code can compile, but the result is code that I'd still (at least personally) rather avoid. The primary reason for iterators to allow their use in generic algorithms. In this case, generic algorithms can do the job quite nicely. For example, let's assume that you wanted to print out the key for every record that the value associated with that key contained whatever value was in searchString. To do that you could write the code like this:

std::copy_if(data.begin(), data.end(),    // The source "range"
    std::ostream_iterator<T>(std::cout, "\n"), // the destination "range"
    [&](T const &v) {
        return std::any_of(v.second.begin(), v.second.end(),
            [&](std::string const &s) {
                return s.find(searchString) != std::string::npos;
            }
        );
    }
);

This depends on an operator<< for the correct type, something like this:

typedef std::pair < std::string, std::vector<std::string>> T;

namespace std {
    std::ostream &operator<<(std::ostream &os, T const &t) {
        return os << t.first;
    }
}

A complete test program could look like this:

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

typedef std::pair < std::string, std::vector<std::string>> T;

namespace std {
    std::ostream &operator<<(std::ostream &os, T const &t) {
        return os << t.first;
    }
}

int main() { 

    std::multimap<std::string, std::vector<std::string>> data{
        { "key1", { "Able", "Bend", "Cell" } },
        { "key2", { "Are", "Dead" } },
        { "key3", { "Bad", "Call" } }
    };

    std::string searchString = "a";

    std::copy_if(data.begin(), data.end(),
        std::ostream_iterator<T>(std::cout, "\n"),
        [&](T const &v) {
            return std::any_of(v.second.begin(), v.second.end(),
                [&](std::string const &s) {
                    return s.find(searchString) != std::string::npos;
                }
            );
        }
    );
}

Result:

key2
key3

Upvotes: 0

Vlad from Moscow
Vlad from Moscow

Reputation: 310990

Unary operators have less priority than postfix operators. In your if statement you need that the unary operator * would be evaluated before member access operator. So you have to write

if ( ( *iter ).find(searchString) != std::string::npos )

Or you could write

if ( iter->find(searchString) != std::string::npos )

Take into account that this record

if ( ( *iter ).find(searchString) )

makes no sense.

Also you could write

for (multimap <string, vector<string> >::const_iterator it = contactInformationMultimap.cbegin();       it != contactInformationMultimap.cend(); ++it)
{
    for ( const std::string &s : it->second )
    {
        if ( s.find(searchString ) != std::string::npos ) /*...*/;
    }                                 
}

Upvotes: 2

Related Questions