Akash De Silva
Akash De Silva

Reputation: 43

Vector searching

Basically I have a load of words in my string vector vector<string> words.

I need to make a function that searches for all the words with "ly" throughout my vector and return them, for example (golly, helpfully, mostly, nearly).

How do I use the std::find_if function to do this or is there any other way that I can do this?

I also need to find words that are longer than 7 letters in my vector, do I still use the std::find_if function with >=7 or something else?

Upvotes: 0

Views: 152

Answers (3)

JeJo
JeJo

Reputation: 32722

First of all, there is a more appropriate algorithm in the standard library called std::copy_if than the std::find_if (for what you have asked).

Secondly, you need to get a different list of words asper different cases. This sounds like having a template function which wraps the std::copy_if and also provide a way to give the custom compare (e.g. a lambda function) functionalities.

Therefore I would suggest something like as follows:

#include <algorithm> // std::copy_if
#include <iterator>  // std::cbegin, std::cend


template<typename Container, typename Predicate>
auto getElelmentsOf(const Container& container, const Predicate condition) /* noexcept */
{
    Container result;
    std::copy_if(std::cbegin(container), std::cend(container), std::back_inserter(result),
        condition);
    return result;
}

Now you could write something like

// all the words with "ly"
const auto words_with_ly = [](const auto& ele) {
    return ele.find(std::string{ "ly" }) != std::string::npos;
};
const auto elemtsOfLy = getElelmentsOf(words, words_with_ly);  // function call


// find words that are longer than 7 letters
const auto words_with_size_7_more = [](const auto& ele) { return ele.size() > 7; };
const auto elemtsOfsize7More = getElelmentsOf(words, words_with_size_7_more);  // function call

(See a Live Demo Online)

Upvotes: 3

MikeCAT
MikeCAT

Reputation: 75062

You can use std::copy_if to get all elements that satisfy some conditions.

#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // for std::copy_if
#include <iterator> // for std::back_inserter

using std::vector;
using std::string;

int main(void) {
    vector<string>words={
        "golly", "hoge", "lyric", "helpfully",
        "mostly", "abcdefg", "nearly", "terrible"
    };
    vector<string> res_ly, res_7;

    // get all words that contains "ly"
    std::copy_if(words.begin(), words.end(), std::back_inserter(res_ly),
        [](const string& x){ return x.find("ly") != string::npos; });

    // get all words that are longer than 7 letters
    std::copy_if(words.begin(), words.end(), std::back_inserter(res_7),
        [](const string& x){ return x.length() > 7; });

    // print what we got
    std::cout << "words with \"ly\":\n";
    for (const string& s : res_ly) std::cout << "  " << s << '\n';
    std::cout << "\nwords longer than 7 letters:\n";
    for (const string& s : res_7) std::cout << "  " << s << '\n';

    return 0;
}

Output:

words with "ly":
  golly
  lyric
  helpfully
  mostly
  nearly

words longer than 7 letters:
  helpfully
  terrible

If you want to use std::find_if, you can repeat searching like this:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // for std::find_if
#include <iterator> // for std::next

using std::vector;
using std::string;

int main(void) {
    vector<string>words={
        "golly", "hoge", "lyric", "helpfully",
        "mostly", "abcdefg", "nearly", "terrible"
    };
    vector<string> res_ly;

    // get all words that contains "ly"
    for (vector<string>::iterator start = words.begin(); ;) {
        vector<string>::iterator next = std::find_if(start, words.end(),
            [](const string& x){ return x.find("ly") != string::npos; });
        if (next == words.end()) {
            break;
        } else {
            res_ly.push_back(*next);
            start = std::next(next, 1);
        }
    }

    // print what we got
    std::cout << "words with \"ly\":\n";
    for (const string& s : res_ly) std::cout << "  " << s << '\n';

    return 0;
}

Upvotes: 2

Vlad from Moscow
Vlad from Moscow

Reputation: 310950

I could suggest the following solution.

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

std::vector<std::string> copy_strings( const std::vector<std::string> &v, const std::string &s )
{
    auto present = [&s]( const auto &item ) 
    {
        return item.find( s ) != std::string::npos; 
    };

    auto n = std::count_if( std::begin( v ), std::end( v ), present );
                            
    std::vector<std::string> result;
    result.reserve( n );
    
    std::copy_if( std::begin( v ), std::end( v ), 
                  std::back_inserter( result ),
                  present );
                  
    return result;                
}

int main() 
{
    std::vector<std::string> v =
    {
        "golly", "helpfully", "mostly", "nearly"
    };
    
    auto result = copy_strings( v, "ly" );
    
    for (const auto &item : result )
    {
        std::cout << item << ' ';
    }
    std::cout << '\n';
    
    return 0;
}

The program output is

golly helpfully mostly nearly

Upvotes: 1

Related Questions