我有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是可以接受的。
答案 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参数重载,提供比较Property
和Object
的比较器。
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::set
或std::equal_range
的对数查找。
答案 2 :(得分:2)
如果未直接公开该值,您甚至可以根据需要定义属性中的键提取器和索引。 (我将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