简体   繁体   中英

Why lambda function doesn't work with std::min_element?

I wrote a program to find the lexicographically minimum string in a vector of strings using std::min_element , but I want to get the minimum string that its length is greater than 1. I tried to do std::min_element with lambda expressions, but I got a compilation error.

I've tried to search for that, but couldn't get anything that solves the problem.

vector<string> names{"Jason", "Peter", "A", "Ac", "O"};
cout << *min_element(names.begin(), names.end(), [](string s) {return s.length() > 1;}) << '\n';

PS: I'm expecting this to print "Ac".

The signature of the comparison function of std::min_element should be equivalent to the following one. This is the reason why you are getting the compilation error:

bool cmp(const Type1 &a, const Type2 &b);

Since operator< is overloaded for std::string to compare lexicographically, you can get the desired result by sorting names with the default comparator and then finding the first element with the length grater than 1 as follows:

Live DEMO

std::vector<std::string> names{"Jason", "Peter", "A", "Ac", "O"};

std::sort(names.begin(), names.end());

const auto it = std::find_if(
                    names.cbegin(), names.cend(),
                    [](const std::string& str){return str.size() > 1;});

if(it != names.cend()){
    std::cout << *it << std::endl;
}

If you want to keep the original vector names , you should copy it before sorting, or use std::set as follows:

Live DEMO (std::set)

std::vector<std::string> names{"Jason", "Peter", "A", "Ac", "O"};

std::set<std::string> s(names.cbegin(), names.cend());

const auto it = std::find_if(
                    s.cbegin(), s.cend(),
                    [](const std::string& str){return str.size() > 1;});

if(it != s.cend()){
    std::cout << *it << std::endl;
}

尽管未回答问题,但解决方案是std::find_if字符串长度对向量进行排序,然后在std::find_if使用lambda函数

The problem is the last parameter. It's expecting a Compare and, being simple, a Compare takes two parameters and returns true or false. See the template definition of min_element taken from cplusplus :

template <class ForwardIterator, class Compare>
ForwardIterator min_element (ForwardIterator first, ForwardIterator last, Compare comp);

You can fix it easily adding another parameter and ignoring it.

vector<string> names{"Jason", "Peter", "A", "Ac", "O"};
cout << *min_element(names.begin(), names.end(), [](string s, string y) {return s.length() > 1;}) << '\n';

You can also search more about Compare as you'll end up using it pretty often. Hope it helps.

You can define the compare function so that an element of length smaller or equal to 1 is greater than a longer element.

bool special_comparison(const std::string &s1, const std::string &s2)
{
    // Make a short string appears greater than a longer one.
    bool shortString1 = s1.size() <= 1;
    bool shortString2 = s2.size() <= 1;
    if (shortString1 != shortString2)
        return shortString2;

    // Regular comparison if both strings are short or both are long.
    return s1 < s2;
}

If the minimum element has a length of 1 (or 0), then it means that all elements are short.

If data is unsorted and you only need to find minimum a single time, that would probably be the fastest approach. Otherwise (if you need to process items in order), it might be better to first sort the data as suggested in other solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM