我调用一个返回std::set<T> const&
的方法,其中T
是类类型。我想要实现的是检查集合是否包含T
类型的对象,其中包含自动测试中断言的特定字段值。应该对多个对象进行此检查。
这是一个简单的例子:
让类型T
为Car
,因此示例set
包含一堆汽车。现在我想找一辆具有特定颜色和特定数量的车门和的汽车,该车在该套装中具有特定的最高速度。如果找到 汽车,则第一个断言为真,并且应找到具有其他字段值的下一辆汽车。
我不允许更改T
的实施。使用Boost就行了。
你会怎么做?
答案 0 :(得分:16)
这取决于T
的实施。让我们坚持你的班级Car
的例子。假设该类看起来像这样:
class Car {
public:
Car(std::string color, unsigned int number_of_doors,
unsigned int top_speed);
// getters for all these attributes
// implementation of operator< as required for std::set
};
operator<
应根据所有属性对Car
的实例进行排序,以便搜索所有可能的属性。否则你会得到不正确的结果。
基本上,你可以只使用这些属性来构建汽车实例。在这种情况下,您可以使用std::set::find
并提供Car
的临时实例,其中包含您要查找的属性:
car_set.find(Car("green", 4, 120));
如果您要搜索Car
仅指定其属性子集的实例(例如所有绿色汽车),则可以将std::find_if
与自定义谓词一起使用:
struct find_by_color {
find_by_color(const std::string & color) : color(color) {}
bool operator()(const Car & car) {
return car.color == color;
}
private:
std::string color;
};
// in your code
std::set<Car>::iterator result = std::find_if(cars.begin(), cars.end(),
find_by_color("green"));
if(result != cars.end()) {
// we found something
}
else {
// no match
}
请注意,第二种解决方案具有线性复杂性,因为它不能依赖于您使用的谓词可能存在或不存在的任何排序。然而,第一个解决方案具有对数复杂度,因为它可以从std::set
的顺序中受益。
如果@Betas对你的问题发表评论,你想在运行时编写谓词,你必须编写一些帮助类来组成不同的谓词。
答案 1 :(得分:1)
遇到这些问题时,我通常会坚持:
std::deque
或std::vector
辆汽车std::multiset
指向汽车的指针,按属性值排序。我小心地将这些容器隐藏在允许我插入汽车的类中。
查询界面可能会有所不同,但通常情况下,您可以利用multiset::equal_range
,std::sort
和std::set_intersection
。
如果你想要一辆红色的沃尔沃汽车......你可以
equal_range
所有红色汽车提取,给你一个迭代器对equal_range
所有沃尔沃汽车提取,给你一个迭代器对set_intersection
到std::deque
。另一种方法是将汽车存储到deque
中,使用std::find
枚举它们并选择满足所有属性的汽车。然而,这可能会有更糟糕的复杂性(这取决于你有多少红色汽车用于表示)
答案 2 :(得分:1)
你需要std::find_if
,谓词函数对象检查你感兴趣的属性。它可能看起来像这样:
struct FindCar {
FindCar(Colour colour, int doors, double top_speed) :
colour(colour), doors(doors), top_speed(top_speed) {}
bool operator()(Car const & car) const {
return car.colour == colour
&& car.doors == doors
&& car.top_speed == top_speed;
}
Colour colour;
int doors;
double top_speed;
};
std::set<Car> const & cars = get_a_set_of_cars();
std::set<Car>::const_iterator my_car =
std::find_if(cars.begin(), cars.end(), FindCar(Red, 5, 113));
在C ++ 0x中,您可以用lambda替换“FindCar”类,以使代码更短。
答案 3 :(得分:0)
您可以尝试重写operator&lt;(const T&amp; a,const T&amp; b)对这些属性强制执行命令,因此std :: set:find(const T&amp; x)将返回第一个不小于x的值。
EJ:
bool operator<(const Car& a, const Car& b)
{
return a.color<b.color || (a.color==b.color && a.doors<b.doors) || (a.color==b.color && a.doors==b.doors && a.top_speed<b.top_speed);
}
std::set<Car> cars;
Car x;
cars.find(x);
答案 4 :(得分:0)
std :: set允许您提供自己的比较功能,如
template < class Key, class Compare = less<Key>,
class Allocator = allocator<Key> > class set;
仅比较您关心的值,它将表现为具有这些值的对象=。请注意,您可能需要一个多重集。
如果您真的关心登录性能,这将是这样做的方法。