使用非密钥类型在集合中进行有效搜索

时间:2011-09-20 15:55:07

标签: c++ stl

我有类似的数据结构:

struct Data { std::string id; Blob data; };

现在我可以使用std::map存储结构并按ID搜索,但我正在寻找一种方法来实现与std::set相同的事情(因为我不需要分开ID和结构)。

std::set::find当然将键类型作为参数,所以我可以做这样的事情(使用适当的构造函数):

set<Data> x; x.find(Data("some_id"));

但我想尽可能避免这种情况。它需要一个允许ID没有数据的构造函数,而且我真的不喜欢构造一个对象,只是将它用作搜索的关键。

所以我的问题是:有更好的方法吗?

5 个答案:

答案 0 :(得分:1)

除非开销明显不可接受,否则我会选择std::map<std::string, Data *>,或者可能std::map<std::string, boost::shared_ptr<Data> >,假设您无权访问本机提供shared_ptr的编译器。

答案 1 :(得分:1)

投入一些构造函数和一个operator<,事情变得非常简单。

 struct Data { 
    std::string id; 
    Blob data; 

    Data(const char* r) : id(r), data() {}
    bool operator<(const Data & r) const {return id<r.id;}

    // rest not needed for demo, but handy
    Data() : id(), data() {}
    Data(std::string&& r) : id(std::move(r)), data() {}
    Data(const std::string& r) : id(r), data() {}
    Data(Data && r) : id(r.id), data(r.data) {}
    Data(const Data & r) : id(r.id), data(r.data) {}
    ~Data() {} 
};

int main() {
    std::set<Data> x;
    x.insert("Apple");
    x.insert("Banana");
    x.insert("Orange");
    x.insert("Grape");

    std::set<Data>::iterator i = x.find("Banana");
    if (i != x.end())
        std::cout << i->id;
    else 
        std::cout << "ERR";
}

http://ideone.com/nVihc结果:

  

香蕉

我承认,这仍然会创建一个“虚拟”数据实例,但它似乎解决了这个问题。

答案 2 :(得分:1)

如果您不反对使用Boost,那么Boost.MultiIndex会使这非常简单,而不会增加任何不必要的低效率。这是一个有效创建set DataData::id个对象的示例,这些对象以#include <string> #include <ios> #include <iostream> #include <boost/multi_index_container.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index/member.hpp> namespace bmi = boost::multi_index; typedef char const* Blob; struct Data { std::string id; Blob data; void display() const { std::cout << "id: " << id << '\n'; } }; typedef bmi::multi_index_container< Data, bmi::indexed_by< bmi::ordered_unique< bmi::member<Data, std::string, &Data::id> > > > DataSet; int main() { Data d1 = { "some_id", nullptr }; Data d2 = { "some_other_id", nullptr }; DataSet set; set.insert(d1); set.insert(d2); set.find("some_id")->display(); // for exposition, find is actually returning an iterator DataSet::const_iterator iter = set.find("some_other_id"); if (iter != set.end()) iter->display(); // set semantics -- newly_added is false here, because the // container already contains a Data object with id "some_id" Data d3 = { "some_id", "blob data" }; bool const newly_added = set.insert(d3).second; std::cout << std::boolalpha << newly_added << '\n'; } 的值为基础:

{{1}}

答案 3 :(得分:0)

更好的方法是将id索引设为data。但是,由于您不想这样做,请尝试使用std::find_if( x.first(), x.end(), --predicate-- ),其中谓词是函数对象或lambda函数谓词,用于将Data与指定的id进行比较。

答案 4 :(得分:0)

我意识到这个问题在此之前被问到了,但是:

从C ++ 14开始,可以在一个集合内进行搜索,而无需创建密钥类型的实例,其中std::set::find的额外重载采用模板化密钥。