wiki2
wiki2

Reputation: 13

check if a vector contains a substring of another vector

I have file names and I need to check if these files end with any extension of the vector extensions; I would like to use some of the algorithms that are in the library instead of how I have done it, is there any way?

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

std::string tail(const std::string &st, const size_t len)
{
    if (len >= st.size())
        return st;
    return st.substr(st.size() - len);
}

std::vector<std::string> filtered_files(const std::vector<std::string>& files, const std::vector<std::string>& extensions) {

    std::vector<std::string> re;
    for(const std::string f : files) {
        for(const std::string ex : extensions) {
            if(ex == tail(f,ex.size())) {
                re.push_back(std::move(f));
                break;
            }
        }
    }
    return re;
}

int main(int argc, char **argv) {

    std::vector<std::string> v{"main.cpp","main.c","main.py"};
    std::vector<std::string> re = filtered_files(v,{".c",".cpp"});
    for(const std::string s  :re) {
        std::cout << s << '\n';
    }

}

Upvotes: 1

Views: 672

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 598434

Have a look at the std::find_if() standard algorithm in place of the inner loop. You can use the std::string::compare() method to perform substring comparisons without having to actually allocate new std::string objects, as your loops and tail() function currently do. The only string allocations you need are for the strings pushed into re (and even that allocation can be avoided if you return a std::vector<std::string*> of pointers that point to the strings in te files vector).

Try this:

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

std::vector<std::string> filtered_files(const std::vector<std::string>& files, const std::vector<std::string>& extensions)
{
    std::vector<std::string> re;

    for(const std::string &f : files)
    {
        if (std::find_if(extensions.begin(), extensions.end(),
            [&](const std::string &ex){
                return (f.size() >= ex.size()) && (f.compare(f.size()-ex.size(), ex.size(), ex) == 0);
            }
        ) != extensions.end())
        {
            re.push_back(f);
        }
    }

    return re;
}

Live Demo

Upvotes: 2

Gerard097
Gerard097

Reputation: 825

There are actually many ways of solving this, personally, this is the way I've achieved it before

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

int main()
{
    std::vector<std::string> v{"main.cpp","main.c","main.py"};
    std::vector<std::string> ext{".cpp", ".c"};
    std::vector<std::string> res;

    for (auto& s : v) {
        auto pos = s.find_last_of('.');            
        if (pos != s.npos) {
            char* str = &s[pos];
            if (std::any_of(ext.begin(), ext.end(), 
                            [str](const string& a) { return str ==  a; })) {
                res.push_back(s);
            }
        }
    }

    for (auto& r : res)
        cout << r << endl;

    return 0;
}

Upvotes: 1

Related Questions