長年のC#の後、C++に戻ったとき、現代はどうなっているのだろうと思いました-C++ 11-配列のフィルタリング方法、つまり、このLinqクエリに似たものをどのように実現できますか?
var filteredElements = elements.Where(Elm => Elm.filterProperty == true);
要素のベクトルをフィルタリングするには(この質問のためにstrings
)?
古いSTLスタイルのアルゴリズム(またはboost::filter_iterator
)明示的なメソッドを定義することを要求することは、今では置き換えられていますか?
_std::copy_if
_ については、cplusplus.comの例を参照してください。
_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
のすべての要素のラムダ式を評価し、true
を返す場合、値をbar
にコピーします。
_std::back_inserter
_により、最初に必要なサイズにサイズを変更することなく、イテレータを使用して(Push_back()
を使用して)bar
の最後に新しい要素を実際に挿入できます。
リストの新しいコピーが実際に必要ない場合、より効率的なアプローチは remove_if
。元のコンテナから要素を実際に削除します。
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; });
唯一の欠点は、ラムダのパラメーター型を明示的に宣言する必要があることです。 decltype(elements):: value_typeを使用しました。正確な型を入力する必要がなく、また汎用性が追加されているためです。あるいは、C++ 14のポリモーフィックラムダを使用すると、タイプを単に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));
C#に相当するC++に対する私の提案
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;
}
使用する-簡単な例を挙げます:
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); });
改善された pjm コードに続く nderscore-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; });
C++ 20では、範囲ライブラリのフィルタービューを使用します。
vec | view::filter([](int a){ return a % 2 == 0; })
vec
の偶数要素を遅延的に返します。
( [range.adaptor.object]/4 および [range.filter] を参照)