2015-01-09 3 views
1

Мне нужно сохранить некоторые объекты в std: set (или любой другой вид таблицы поиска) и выполнить поиск по имени.Поиск объектов по имени на std :: set

Например, предположим, что у меня есть класс, как (псевдокод):

class Person 
{ 
    std::string mName; 
    int mAge; 
    ... //etc 
}; 

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

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

Есть ли способ сохранить этот тип объекта в std :: set (или любом другом контейнере) и выполнить поиск по ключу (а не к объекту)?

Спасибо

+0

Возможно, это дублированный вопрос, но я не думаю, что выбранный вариант подходит. –

+0

P.S. В C++ 14 вы сможете указать параметр 'find', который * не * точный тип заданного элемента. Подробнее см. Http://en.cppreference.com/w/cpp/container/set/find. –

+0

Как вы определяете заказ для 'Person'? – Praetorian

ответ

1

Пожалуйста, обратите внимание на повышение :: навязчивые контейнеры, в частности boost::intrusive::set.

В обмен на некоторую уклонение класса предметов появляется большая гибкость. Углификация происходит из-за того, что элемент должен выводиться из определенного класса или должен объявлять специальную переменную-член для хранения древовидных связей. Это все красиво завернуто.

Что касается конкретных запросов, повышение :: навязчивым :: Набор позволяет

  • повторного mName для ключа (не в отличие от станд :: комплект)
  • lookup Person строкой (в отличие от станд :: установить там нет необходимости строить Person, чтобы сделать поиск)
+0

Да, я знаю об этом навязчивом, но я не хочу делать это навязчивым в этом случае :) – bcsanches

0

вы можете использовать std::find_if, например, если у вас есть std::set<Person> people

auto match = std::find_if(people.begin(), people.end(), [](const Person& foo){return foo.mName == "Bob";}); 
if (match != people.end()) 
{ 
    std::cout << "Found Bob!" 
} 

Так что вам не нужно создавать полный объект Person, только std::string, чтобы соответствовать их названию, например.

+1

Это очень медленный способ сделать это. –

+0

@MarkRansom: на самом деле это самый медленный способ, который не извращает его путь, чтобы быть медленным. То есть идеальное решение Agile v1.0. Если он пройдет тесты, отправьте его! Если это не так, задайте другой вопрос ;-) –

+0

Это мое беспокойство, это будет линейное право поиска? – bcsanches

0

Таким образом, вы можете использовать find_if для достижения этой цели:

struct find_by_name { 
    find_by_name(const std::string & name) : name(name) {} 
    bool operator()(const Person & person) { 
     return person.name == name; 
    } 
private: 
    std::string name; 
}; 

// in your code 

std::set<Person>::iterator result = std::find_if(people.begin(), people.end(), 
               find_by_name("Ben")); 
if(result != people.end()) { 
    // we found something 
} 
else { 
    // no match 
} 

Таким образом, вы поиск только на основе генерируемой строки (в структурах) и его очень гибкий, вы можете инициализировать его с любой строкой, вы можете также используйте его для поиска person в любом контейнере, который реализует итератор.

+0

Определяет ли find_if значение is set и выполняет «быстрый» поиск? – bcsanches