任何人都可以推荐一种漂亮而整洁的方法来实现这一目标:
float CalculateGoodness(const Thing& thing);
void SortThings(std::vector<Thing>& things)
{
// sort 'things' on value returned from CalculateGoodness, without calling CalculateGoodness more than 'things.size()' times
}
显然,我可以将std::sort
与调用CalculateGoodness
的比较函数一起使用,但随后将Thing
调用几次,因为它与其他元素进行比较,这是不好的如果CalculateGoodness
很贵。我可以创建另一个std::vector
只是为了存储评分和std::sort
,并以同样的方式重新排列things
,但我看不出这样做的整洁方式。有什么想法吗?
编辑:道歉,我应该说而不修改Thing
,否则这是一个相当容易解决的问题:)
答案 0 :(得分:4)
在排序之前,您可以调用CalculateGoodness
来调用每个元素,然后CalculateGoodness
只更新内部成员变量。然后,您可以根据该成员变量进行排序。
如果您无法修改类型,另一种可能性是为您的对象及其先前计算的值存储某种std::map
。您的排序函数将使用充当缓存的映射。
答案 1 :(得分:4)
我可以想到一个简单的转换(两个)来获得你想要的东西。您可以将std::transform
与合适的谓词一起使用。
std::vector<Thing>
至std::vector< std::pair<Result,Thing> >
Tadaam:)
编辑:尽量减少副本数量
std::vector<Thing>
至std::vector< std::pair<Result,Thing*> >
这样您只需复制每个Thing
一次。值得注意的是,请记住sort
执行副本,因此值得使用。
因为我感觉很自负:
typedef std::pair<float, Thing*> cached_type;
typedef std::vector<cached_type> cached_vector;
struct Compute: std::unary_function< Thing, cached_type >
{
cached_type operator()(Thing& t) const
{
return cached_type(CalculateGoodness(t), &t);
}
};
struct Back: std::unary_function< cached_type, Thing >
{
Thing operator()(cached_type t) const { return *t.second; }
};
void SortThings(std::vector<Thing>& things)
{
// Reserve to only allocate once
cached_vector cache; cache.reserve(things.size());
// Compute Goodness once and for all
std::transform(things.begin(), things.end(),
std::back_inserter(cache), Compute());
// Sort
std::sort(cache.begin(), cache.end());
// We have references inside `things` so we can't modify it
// while dereferencing...
std::vector<Thing> local; local.reserve(things.size());
// Back transformation
std::transform(cache.begin(), cache.end(),
std::back_inserter(local), Back());
// Put result in `things`
swap(things, local);
}
提供通常的警告:在我的头顶上,可能会杀死小猫......
答案 2 :(得分:2)
我赞成Brian's answer,因为它显然最能满足您的需求。但是你应该考虑的另一个解决方案是只是简单地写它。处理器每天都变得越来越强大。使其正确并继续前进。您可以稍后对其进行分析,看看CalculateGoodness
是否确实是瓶颈。
答案 3 :(得分:1)
我会创建一对评级和事物,每次调用一次CalculateGoodness,然后对评级进行排序。如果适用,您也可以将其移动到从评级到事物的地图
另一种选择是将Thing本身的CalculateGoodness缓存为一个简单的字段,或者将CalculateGoodness作为Thing的方法(确保缓存是可变的,因此const Things仍然有效)
答案 4 :(得分:1)
执行单独vector
事情的一种简洁方法可能是实际创建vector< pair<float, Thing*> >
,其中第二个元素指向具有相应Thing
值的float
对象。如果您按vector
值对float
进行排序,则可以对其进行迭代并按正确的顺序读取Thing
个对象,可能会将它们播放到另一个vector
或{{ 1}}所以它们最终按顺序存储。