Idiomatic C++ for finding a range of equal length strings, given a vector of strings (ordered by length)
given a std::vector< std::string >
, the vector is ordered by string length, how can I find a range of equal length strength?
I am looking forward an idiomatic solution in C++.
I have found this solution:
// any idea for a better name? (English is not my mother tongue)
bool less_length( const std::string& lhs, const std::string& rhs )
{
return lhs.length() < rhs.length();
}
std::vector< std::string > words;
words.push_back("ape");
words.push_back("cat");
words.push_back("dog");
words.push_back("camel");
size_t length = 3;
// this will give a range from "ape" to "dog" (included):
std::equal_range( words开发者_StackOverflow社区.begin(), words.end(), std::string( length, 'a' ), less_length );
Is there a standard way of doing this (beautifully)?
I expect that you could write a comparator as follows:
struct LengthComparator {
bool operator()(const std::string &lhs, std::string::size_type rhs) {
return lhs.size() < rhs;
}
bool operator()(std::string::size_type lhs, const std::string &rhs) {
return lhs < rhs.size();
}
bool operator()(const std::string &lhs, const std::string &rhs) {
return lhs.size() < rhs.size();
}
};
Then use it:
std::equal_range(words.begin(), words.end(), length, LengthComparator());
I expect the third overload of operator()
is never used, because the information it provides is redundant. The range has to be pre-sorted, so there's no point the algorithm comparing two items from the range, it should be comparing items from the range against the target you supply. But the standard doesn't guarantee that. [Edit: and defining all three means you can use the same comparator class to put the vector in order in the first place, which might be convenient].
This works for me (gcc 4.3.4), and while I think this will work on your implementation too, I'm less sure that it is actually valid. It implements the comparisons that the description of equal_range
says will be true of the result, and 25.3.3/1 doesn't require that the template parameter T
must be exactly the type of the objects referred to by the iterators. But there might be some text I've missed which adds more restrictions, so I'd do more standards-trawling before using it in anything important.
Your way is definitely not unidiomatic, but having to construct a dummy string with the target length does not look very elegant and it isn't very readable either.
I'd perhaps write my own helper function (i.e. string_length_range
), encapsulating a plain, simple loop through the string list. There is no need to use std::
tools for everything.
std::equal_range
does a binary search. Which means the words
vector must be sorted, which in this case means that it must be non-decreasing in length.
I think your solution is a good one, definitely better than writing your own implementation of binary search which is notoriously error prone and hard to prove correct.
If doing a binary search was not your intent, then I agree with Alexander. Just a simple for loop through the words is the cleanest.
精彩评论