函数返回包含输入容器特定元素的容器

时间:2018-08-07 13:54:17

标签: c++ stl copy

我有一个vectorlist,我只想将代码应用于特定元素。例如

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());
    }
}

2 个答案:

答案 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;
    }
));