web-dev-qa-db-ja.com

STLコンテナをフィルタリングする最新の方法は?

長年のC#の後、C++に戻ったとき、現代はどうなっているのだろうと思いました-C++ 11-配列のフィルタリング方法、つまり、このLinqクエリに似たものをどのように実現できますか?

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

要素のベクトルをフィルタリングするには(この質問のためにstrings)?

古いSTLスタイルのアルゴリズム(またはboost::filter_iterator明示的なメソッドを定義することを要求することは、今では置き換えられていますか?

59
ATV

_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の最後に新しい要素を実際に挿入できます。

73

リストの新しいコピーが実際に必要ない場合、より効率的なアプローチは remove_if 。元のコンテナから要素を実際に削除します。

32
djhaskin987

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));
22
user2478832

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); });
9
pjm

改善された 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; });
7
AlexP11223

C++ 20では、範囲ライブラリのフィルタービューを使用します。

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

vecの偶数要素を遅延的に返します。

[range.adaptor.object]/4 および [range.filter] を参照)

3
L. F.