过滤STL容器的现代方法?

时间:2014-01-18 13:19:20

标签: c++ c++11 stl

经过多年的C#回到C ++后,我想知道现代化的东西:C ++ 11 - 过滤数组的方式,即我们怎样才能实现类似于Linq查询的东西:

var filteredElements = elements.Where(elm => elm.filterProperty == true);

为了这个问题,为了过滤元素向量(strings)?

我真诚地希望现在可以取代旧的STL样式算法(甚至像boost::filter_iterator那样需要显式方法的扩展)?

6 个答案:

答案 0 :(得分:63)

请参阅cplusplus.com中std::copy_if的示例:

std::vector<int> foo = {25,15,5,-5,-15};
std::vector<int> bar;

// copy only positive numbers:
std::copy_if (foo.begin(), foo.end(), std::back_inserter(bar), [](int i){return i>=0;} );

std::copy_if在此计算foo中每个元素的lambda表达式,如果它返回true,则会将值复制到bar

std::back_inserter允许我们在bar(使用push_back())的末尾实际插入新元素和迭代器,而不必先将其大小调整为所需的大小。

答案 1 :(得分:24)

如果您实际上不需要列表的新副本,则更有效的方法是remove_if,它实际上会从原始容器中删除元素。

答案 2 :(得分:21)

我认为Boost.Range也值得一提。生成的代码非常接近原始代码:

#include <boost/range/adaptors.hpp>

// ...

using boost::adaptors::filtered;
auto filteredElements = elements | filtered([](decltype(elements)::value_type const& elm)
    { return elm.filterProperty == true; });

唯一的缺点是必须明确声明lambda的参数类型。我使用了decltype(elements):: value_type,因为它避免了拼写出确切的类型,并且还增加了一些通用性。或者,使用C ++ 14的多态lambda,类型可以简单地指定为auto:

auto filteredElements = elements | filtered([](auto const& elm)
    { return elm.filterProperty == true; });

filteredElements是一个适合遍历的范围,但它基本上是原始容器的视图。如果您需要的是另一个装满满足条件的元素副本的容器(这样它与原始容器的生命周期无关),它可能看起来像:

using std::back_inserter; using boost::copy; using boost::adaptors::filtered;
decltype(elements) filteredElements;
copy(elements | filtered([](decltype(elements)::value_type const& elm)
    { return elm.filterProperty == true; }), back_inserter(filteredElements));

答案 3 :(得分:10)

在C ++ 20中,使用范围库中的过滤器视图:

vec | view::filter([](int a){ return a % 2 == 0; })

懒惰地返回vec中的偶数元素。

(请参见[range.adaptor.object]/4[range.filter]

答案 4 :(得分:8)

我建议用C ++等同于C#

ERROR:  invalid input syntax for integer: """"

定义一个模板函数,传递一个lambda谓词来进行过滤。模板函数返回过滤结果。例如:

var filteredElements = elements.Where(elm => elm.filterProperty == true);

使用 - 给出一个简单的例子:

template<typename T>
vector<T> select_T(vector<T> inVec, function<bool(const T&)> predicate)
{
  vector<T> result;
  copy_if(inVec.begin(), inVec.end(), back_inserter(result), predicate);
  return result;
}

答案 5 :(得分:6)

根据pjm条建议,改进了underscore-d代码:

template <typename Cont, typename Pred>
Cont filter(const Cont &container, Pred predicate) {
    Cont result;
    std::copy_if(container.begin(), container.end(), std::back_inserter(result), predicate);
    return result;
}

用法:

std::vector<int> myVec = {1,4,7,8,9,0};

auto filteredVec = filter(myVec, [](int a) { return a > 5; });