4

ときどき、コンテナーの要素のサブセットを反復処理する必要があるか、単にそれらを抽出して残りを無視したいことがあります。私はboost::range::adaptors::filteredこの怠惰なコレクションを作成するために使用することになります。

for(auto&& i : container | filtered(predicate)) {
  // .. do stuff
}

STL に収集アルゴリズム (Ruby の収集のように) がない理由はありますか (同じではない copy_if しかありません)。またはそれを使用しない理由はありますか?

可能な実装は次のとおりです。

template<class Container, class Predicate>
Container collect(Container&& c, Predicate&& p) {
  Container n;
  for(auto&& i : c) {
    if(p(i)) {
      n.push_back(i);
    }
  }
  return n;
}

しかし、 alazy_collectはコピーを避けるためにも役立つかもしれません。

以下のすべての答えは素晴らしいです。全部マークできればいいのに。については知りませんでしたstd::back_inserter。アイテムの収集は次のように簡単になりました。

boost::copy( orig | filtered(predicate), std::back_inserter(collection));
4

3 に答える 3

6

標準アルゴリズムは、コンテナーに対して直接操作を行いません (コンテナーの作成または破棄、またはサイズの変更)。それらは反復子の範囲で動作し、アルゴリズムが行う唯一の変更は、反復子による割り当てによるものです。

したがって、提案された操作は完全に標準アルゴリズムの範囲外です。たぶん、これを含め、標準には汎用コンテナ操作の大きな追加セットが「あるはず」ですが、「STLの哲学」はイテレータで操作することです。

あなたが提案する非遅延操作はstd::back_inserter、and std::copy_if(オプションで移動イテレータを使用) またはmove_if(自分でロールする場合) を使用して実行できます。std::copy_ifC++03 にはありませんでしたが、それは偶然の見落としでした。

怠惰なバージョンは、標準コンポーネントを接続するだけでは実行できません。中間ストレージなしで、あるアルゴリズムの「出力」を別のアルゴリズムの「入力」に直接チェーンする明確な方法はありません。そのため、Boost はさまざまな興味深い反復子と範囲を提供します。

なぜ C++11 に組み込まれなかったのかはわかりませんが、C++11 について注意すべきことの 1 つは、かなり遅かったということです。提案は時間が足りなかったために取り下げられたので、その理由は「既知の既存のワークロードを考えると、提案するほど重要であるとは考えられなかった」という単純なものかもしれません。

特定の実装に関しては、すべてのコンテナーに がpush_backあるわけではないため、おそらくContainerテンプレート パラメーター名として使用しないでください。PushBackSequence要件をより説明します。

于 2013-03-21T10:15:41.197 に答える
5

コメントから:

copy_if を使用する場合、必要な容量を事前に知る必要があります

それは真実ではない。バックインサーターstd::copy_ifと一緒に使用できます:

#include <algorithm> // For std::copy_if
#include <iterator> // For std::back_inserter
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> v(10);
    std::iota(begin(v), end(v), 0); // Fills the vector with 0..9

    std::vector<int> out;
    std::copy_if(begin(v), end(v), back_inserter(out), [] (int x) 
    //                             ^^^^^^^^^^^^^^^^^^
    {
        return x > 4; 
    });

    for (auto x : out) { std::cout << x << " "; }
}

これが実際のです。

また、反復子のペアによって定義された範囲ではなく、コンテナーに対して直接機能する関数が必要な場合は、次のヘルパーを記述できます。

template<typename C1, typename C2, typename P>
void cont_copy_if(C1&& src, C2&& dst, P&& p)
{
    std::copy_if(
        begin(std::forward<C1>(src)),
        end(std::forward<C1>(src)),
        back_inserter(std::forward<C2>(dst)),
        std::forward<P>(p)
        );
}

このように使用するだけです:

int main()
{
    std::vector<int> v(10);
    std::iota(begin(v), end(v), 0);

    std::list<int> out;
//  ^^^^^^^^^
//  You could use a different destination container

    cont_copy_if(v, out, [] (int x) { return x > 4; });
//  ^^^^^^^^^^^^

    for (auto x : out) { std::cout << x << " "; }
}

そしてもちろんlive example .

于 2013-03-21T10:17:31.710 に答える
5

これはどう:

#include <algorithm>
#include <iterator>

std::copy_if(container.begin(), container.end(), std::back_inserter(result), []{...})

はどこcontainerから収集したいresultコンテナで、 はコレクションを格納するコンテナです。

于 2013-03-21T10:15:18.473 に答える