Определение <
для std::pair
реализует лексикографический порядок, а ""
является минимальным элементом для строк.Комбинируя это, мы получаем:
typedef std::pair<std::string, std::string> StringPair;
typedef std::set<StringPair> Set;
std::string const* find_first(Set const& s, std::string const& key) {
Set::const_iterator const it = s.lower_bound(std::make_pair(key, ""));
// Check that it actually points to a valid element whose key is of interest.
if (it == s.end() or it->first != key) { return 0; }
// Yata!
return &it->second;
}
Трюк использует lower_bound
соответственно.
Возвращает итератор, указывающий на первый элемент, который сравнивается не менее чем value
.
- Если он возвращает
end()
, то он не нашел ничего интересного. - В противном случае
it->first >= key
, поэтому мы избавляемся от случая >
(изнас это не интересует)
Хотелось бы отметить, что это возвращает только первый элемент диапазона.Если вас интересуют все элементы, попробуйте:
typedef std::pair<Set::const_iterator, Set::const_iterator> SetItPair;
SetItPair equal_range_first(Set const& s, std::string const& key) {
StringPair const p = std::make_pair(key, "");
return std::make_pair(s.lower_bound(p), s.upper_bound(p));
}
Это вернет полный диапазон узлов в s
, чей первый элемент равен key
.Затем вам просто нужно перебрать этот диапазон:
for (Set::const_iterator it = range.first; it != range.second; ++it) {
// do something
}
И вам даже не нужно беспокоиться о том, закончился ли возврат lower_bound
или upper_bound
или нет.
- если
lower_bound
возвращает end()
, то upper_bound
и цикл пропускаются - , если
lower_bound
указывает на узел, для которого it->first > key
, то upper_bound
будет указыватьк тому же узлу, и цикл пропускается
Это сила диапазонов: нет необходимости делать специальные проверки, диапазоны просто оказываются пустыми, когда нет совпадения, и поэтому цикл завершаетсяони ... пропускаются за одну проверку.