经过多年的C#回到C ++后,我想知道现代化的东西:C ++ 11 - 过滤数组的方式,即我们怎样才能实现类似于Linq查询的东西:
var filteredElements = elements.Where(elm => elm.filterProperty == true);
为了这个问题,为了过滤元素向量(strings
)?
我真诚地希望现在可以取代旧的STL样式算法(甚至像boost::filter_iterator
那样需要显式方法的扩展)?
答案 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
中的偶数元素。
答案 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; });