经过多年的C#回到C++之后,我想知道现代 - 读取:C++ 11 - 过滤数组的方式是什么,即我们如何实现类似于Linq查询的东西:
var filteredElements = elements.Where(elm => elm.filterProperty == true);
Run Code Online (Sandbox Code Playgroud)
为了过滤元素的向量(strings为了这个问题)?
我真诚地希望现在可以取代需要定义显式方法的旧STL样式算法(甚至扩展boost::filter_iterator)?
Seb*_*ann 82
请参阅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;} );
Run Code Online (Sandbox Code Playgroud)
std::copy_if计算foo此处每个元素的lambda表达式,如果返回true则将值复制到bar.
将std::back_inserter允许我们实际上在插入的最后新元素bar(使用push_back())同一个迭代,而不必首先将它调整到所需的大小.
djh*_*987 34
如果您实际上不需要列表的新副本,则更有效的方法是remove_if实际从原始容器中删除元素.
use*_*832 23
我认为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; });
Run Code Online (Sandbox Code Playgroud)
唯一的缺点是必须明确声明lambda的参数类型.我使用了decltype(elements):: value_type,因为它避免了拼写出确切的类型,并且还增加了一些通用性.或者,使用C++ 14的多态lambda,可以将类型简单地指定为auto:
auto filteredElements = elements | filtered([](auto const& elm)
{ return elm.filterProperty == true; });
Run Code Online (Sandbox Code Playgroud)
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));
Run Code Online (Sandbox Code Playgroud)
我对C++等效C#的建议
var filteredElements = elements.Where(elm => elm.filterProperty == true);
Run Code Online (Sandbox Code Playgroud)
定义传递lambda谓词以进行过滤的模板函数.模板函数返回过滤结果.例如:
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;
}
Run Code Online (Sandbox Code Playgroud)
使用 - 给出一个简单的例子:
std::vector<int> mVec = {1,4,7,8,9,0};
// filter out values > 5
auto gtFive = select_T<int>(mVec, [](auto a) {return (a > 5); });
// or > target
int target = 5;
auto gt = select_T<int>(mVec, [target](auto a) {return (a > target); });
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
用法:
std::vector<int> myVec = {1,4,7,8,9,0};
auto filteredVec = filter(myVec, [](int a) { return a > 5; });
Run Code Online (Sandbox Code Playgroud)
In C++20, use filter view from the ranges library:
vec | view::filter([](int a){ return a % 2 == 0; })
Run Code Online (Sandbox Code Playgroud)
lazily returns the even elements in vec.
(See [range.adaptor.object]/4 and [range.filter])
| 归档时间: |
|
| 查看次数: |
45497 次 |
| 最近记录: |