c ++ set :: find by object property

时间:2013-02-28 20:47:50

标签: c++ qt boost map unordered-map

我有object property,这是此对象的方法所必需的:

class Object {
   Property property;
}

然后我需要对这个对象进行分组。要求在该组中只有具有唯一属性的对象。在set中对这些对象进行分组是很自然的。我定义了一个operator<,或者它是unordered_set operator==hash()。没关系。然后出现另一个问题。我需要使用property在集合中找到这些对象。所以我需要创建一个Object类型的对象,并将此属性赋给其字段。这就是我不喜欢的地方。

另一种方法是制作map。并复制或指向对象的属性,然后将它们用作地图中的键。我认为这也是一项双重工作。

我想要set之类的东西,但能够使搜索不使用整个对象,而是使用对象的属性来查找它。例如,我定义了以下内容:

class Object {
   Property property;
   bool operator<(Object obj) { return property < obj.property; }
   bool operator<(Property obj) { return property < obj.property; }
};
some::set<Object> objSet;

然后我可以做以下事情:

Object obj;
objSet.insert(obj);
objSet.find(obj.property);

你可以提供一些容器的实现来帮助我吗?提升,qt是可以接受的。

3 个答案:

答案 0 :(得分:5)

Boost Multi-Index array可能就是您所需要的。此示例multiple sort on a single set与您正在寻找的内容非常匹配。

typedef multi_index_container<
  Object,
  indexed_by<
    ordered_unique<member<Object,Property,&Object::property> >
  > 
> object_set;

object_set oset;
Property prop;
oset.find( prop );

答案 1 :(得分:3)

您可以使用std::equal_range的4参数重载,提供比较PropertyObject的比较器。

struct Cmp
{
    bool operator() ( const Object& o, const Property& p ) const
    {
        return o.property < p;
    }
    bool operator() ( const Property& p, const Object& o ) const
    {
        return p < o.property;
    }
};

std::set<Object> s = ....;
Property property_val = ....;
auto r = std::equal_range(s.begin(),s.end(), property_val, Cmp());

另一个选择是使用std::find_if和一个合适的一元谓词。但是你不会受益于std::setstd::equal_range的对数查找。

答案 2 :(得分:2)

我选择Boost Multi Index

如果未直接公开该值,您甚至可以根据需要定义属性中的键提取器和索引。 (我将Property作为一个struct和Object公开以便于打印,但只要Property :: get_value()是公共的,这就行了)

#include <iostream>
#include <string>
#include <algorithm>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/optional.hpp>

struct by_property_value{};
struct byseq{};
struct by_id{};

struct Property{
    int value;
    std::string name;

    int get_value() const{
        return value;
    }
};

class Object {
public:
   int id;
   Property property;
};

Object make_object(const int&id, const int& value, const std::string& name){
    Object res;
    res.id = id;
    Property p;
    p.value = value;
    p.name = name;
    res.property = p;
    return res;
}

bool operator<(const Object& lhs, const Object& rhs){
    return lhs.id < rhs.id;
}



using namespace boost;
using namespace boost::multi_index;

struct property_value_key_extractor{
    typedef int result_type;

    result_type operator()(const Object& o) const{
        return o.property.get_value();
    }
};

typedef multi_index_container<
    Object,
    indexed_by<
        sequenced<tag<byseq> >
        , ordered_unique<tag<by_id>,member<Object,int,&Object::id> >
        , ordered_non_unique<tag<by_property_value> , property_value_key_extractor >
    >
> Objects;


using namespace std;
int main(int argc, char *argv[]) {

    Objects objects;
    objects.push_back(make_object(1,1000,"a"));
    objects.push_back(make_object(2,200,"b"));
    objects.push_back(make_object(3,50,"c"));

    typedef Objects::index<by_property_value>::type objects_by_property_value;
    typedef objects_by_property_value::iterator property_value_iterator;

    property_value_iterator it = objects.get<by_property_value>().find(200);

    if(it != objects.get<by_property_value>().end()){
        cout << it->id << " " << it->property.get_value() << " " << it->property.name << endl;
    }

    cout << "Print by propety value" << endl;

    for(property_value_iterator it = objects.get<by_property_value>().begin(); it != objects.get<by_property_value>().end(); it++ ){
        cout << it->id << " " << it->property.get_value() << " " << it->property.name << endl;
    }

}

输出:

  

2 200 b
  按照价值打印
  3 50 c
  2 200 b
  1 1000 a