2012-03-23 2 views
5

Так у меня есть набор pairs<string ,string>C++ set для парного элемента?

И я хочу использовать find() для поиска одной строки, которая была бы в «первый» пару, а затем, если я нахожу эту строку в первом я хочу вернуться вторым от этой функции.

Моя текущая попытка ..

myList::iterator i; 

i = theList.find(make_pair(realName, "*")); 

return i->second; 
+7

Почему вы не используете «карту»? Другие примечания: если это 'std :: set', почему он называется' myList'? Вы создали функцию сравнения для 'std :: pair'? Как это выглядит? –

ответ

2

Вы можете использовать std::set<std::pair<std::string, std::string> > для этого, но вы будете нуждаться в пользовательских объект сравнения для этого, потому что оператор отношения пары принимает оба элемента для этого. Тем не менее, похоже, что вы действительно должны использовать std::map<std::string, std::string>.

+1

Я не согласен, семантика будет совсем иной, в частности, неспособность хранить несколько элементов с одним и тем же «ключом». «Мультимап» может быть ближе к семантике, но тогда не будет гарантировать уникальность пары, которая также может быть желательной. Не зная требования, ваш ответ действительно является выстрелом в темноте ... –

1

Определение < для 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 будет указывать на тот же узел, и цикл пропускается

Это сила диапазонов: нет необходимости делать специальные проверки, диапазоны просто заканчиваются пустым, когда нет совпадения, и поэтому цикл над ними ... пропускается с одной проверкой.

+0

Что делать, если второй элемент является int? – user3522401

6

Является ли C++ 11 приемлемым?

auto it = find_if(theList.begin(), theList.end(), 
    [&](const pair<string, string>& val) -> bool { 
     return val.first == realName; 
    }); 

return it->second; 

Или в C++ 03, сначала определим функтор:

struct MatchFirst 
{ 
     MatchFirst(const string& realName) : realName(realName) {} 

     bool operator()(const pair<string, string>& val) { 
       return val.first == realName; 
     } 

     const string& realName; 
}; 

затем вызвать его следующим образом:

myList::iterator it = find_if(a.begin(), a.end(), MatchFirst(realName)); 
return it->second; 

Это будет возвращать только первый матч, но из вашего вопрос, похоже, это все, что вы ожидаете.

Смежные вопросы