我有一个vector
或list
,我只想将代码应用于特定元素。例如
class Container : public std::vector<Element*>
或
class Container : public std::list<Element*>
并且:
Container newContainer = inputContainer.Get(IsSomething);
if (!newContainer.empty()) {
for (Element* const el: newContainer ) {
[some stuff]
}
} else {
for (Element* const el : inputContainer) {
[some stuff]
}
}
我已如下编写成员函数Get()
。
template<typename Fn>
auto Container::Get(const Fn& fn) const {
Container output;
std::copy_if(cbegin(), cend(), std::inserter(output, output.end()), fn);
return output;
}
和IsSomething
将是lambda,例如
auto IsSomething= [](Element const* const el)->bool { return el->someBool; };
从性能角度来看:这是一个好方法吗?还是复制并删除会更好?
template<typename Fn>
auto Container::Get(const Fn& fn) const {
Container output(*this);
output.erase(std::remove_if(output.begin(), output.end(), fn), end(output));
return output;
}
还是有更好的方法?
由于我的上一个示例可以用更好的方式编写,因此让我们展示另一个示例:
while (!(container2 = container1.Get(IsSomething)).empty()&&TimesFooCalled<SomeValue)
{
Container container3(container2.Get(IsSomething));
if (!container3.empty()) {
Foo(*container3.BestElement());
} else {
Foo(*container2.BestElement());
}
}
答案 0 :(得分:2)
没有回答您的直接问题,但是请注意,您可以实现原始算法而无需复制任何内容。像这样:
bool found = false;
for (Element* const el: inputContainer) {
if (IsSomething(el)) {
found = true;
[some stuff]
}
}
if (!found) {
for (Element* const el : inputContainer) {
[some stuff]
}
}
答案 1 :(得分:1)
我通常使用的模式是这样的:
for(auto const * item : inputContainer) if(IsSomething(item)) {
// Do stuff with item
}
这通常已经足够好了,所以其他方法似乎过大了。
为了获得更好的性能,最好不要复制或从列表中删除元素。以我的经验,由于缓存原因,只浏览列表一次会更快。因此,这就是我要从列表中查找一个或另一个“最佳”值的方法:
auto const isBetter = std::greater<Element>();
Element const * best = nullptr, const * alt_best = nullptr;
for(Element const * current : inputContainer) {
if(IsSomething(current)) {
if(!best || isBetter(*best, *current)) best = current;
} else {
if(!alt_best || isBetter(*alt_best, *current)) alt_best = current;
}
}
if(best) {
// do something with best
} else if(alt_best) {
// do something with alt_best
} else {
// empty list
}
如果您发现自己做了很多事情,或者想将其作为类接口的一部分,则可以考虑编写一个迭代器来跳过不喜欢的元素。
如果您实际上要从列表中删除该项目,则可以执行以下操作:
inputContainer.erase(std::remove_if(std::begin(inputContainer), std::end(inputContainer),
[](Element const *item) {
if(IsSomething(item)) {
// Do something with item
return true;
}
return false;
}
));