Reputation: 101
I'm trying to come up with a lambda that will allow std::equal_range
to return a range in which the string searched for exists as a prefix. As that probably isn't worded right, an example:
Given the vector of strings:
I would expect the iterators returned to be
How would I write a comparison lambda for std::equal_range
that accomplishes this, or is std::equal_range
not the right tool for this job?
Upvotes: 3
Views: 874
Reputation: 48615
I think you simply need to make the comparator compare only the length of the prefix against the elements like this:
std::vector<std::string> v
{
"C:/users/andy/documents/screenshot.jpg",
"C:/users/bob/desktop/file.txt",
"C:/users/bob/desktop/picture.png",
"C:/users/bob/desktop/video.mp4",
"C:/users/john/desktop/note.txt",
};
std::sort(std::begin(v), std::end(v));
std::string const prefix = "C:/users/bob/desktop/";
auto lb = std::lower_bound(std::begin(v), std::end(v), prefix);
// For the upper bound we want to view the vector's data as if
// every element was truncated to the size of the prefix.
// Then perform a normal match.
auto ub = std::upper_bound(lb, std::end(v), prefix,
[&](std::string const& s1, std::string const& s2)
{
// compare UP TO the length of the prefix and no farther
if(auto cmp = std::strncmp(s1.data(), s2.data(), prefix.size()))
return cmp < 0;
// The strings are equal to the length of the prefix so
// behave as if they are equal. That means s1 < s2 == false
return false;
});
// make the answer look like we used std::equal_range
// (if that's what's needed)
auto range = std::make_pair(lb, ub);
for(auto itr = range.first; itr != range.second; ++itr)
std::cout << *itr << '\n';
Output:
C:/users/bob/desktop/file.txt
C:/users/bob/desktop/picture.png
C:/users/bob/desktop/video.mp4
To explain why this works imagine taking the vector and sorting it. Then imagine visiting every element and truncating them to the length of the prefix. You would be left with a sorted vector with no elements longer than the prefix. At that point a simple std::equal_range
would do what you require. Thus, all we need to do is construct a comparator that behaves as if the container elements had been truncated to the length of the prefix and use that comparator in our std::equal_range
search (or twin std::lower_bound/upper_bound
search).
Upvotes: 2