std :: setのstd :: back_inserter?


94

これは簡単な質問だと思います。私はこのようなことをする必要があります:

std::set<int> s1, s2;
s1 = getAnExcitingSet();
std::transform(s1.begin(), s1.end(), std::back_inserter(s2), ExcitingUnaryFunctor());

もちろん、std::back_inserterがないため機能しませんpush_backstd::inserterイテレータも必要ですか?使っstd::inserterたことがないのでどうすればいいかわかりません。

誰かがアイデアを持っていますか?


もちろん、私のもう1つのオプションは、のベクトルを使用して、s2後でそれを並べ替えることです。多分それは良いですか?

回答:


139

setpush_back要素の位置はセットのコンパレーターによって決定されるため、ありません。使用std::inserterして渡す.begin()

std::set<int> s1, s2;
s1 = getAnExcitingSet();
transform(s1.begin(), s1.end(), 
          std::inserter(s2, s2.begin()), ExcitingUnaryFunctor());

挿入イテレータは、イテレータに書き込まれたときにイテレータに渡された値がs2.insert(s2.begin(), x)どこxであるかを呼び出します。セットは、挿入する場所のヒントとしてイテレータを使用します。あなたも使用できますs2.end()


2
以来inserter(vec, vec.end())ベクトルの作品、あまりにも、なぜ最初の場所で誰でも利用back_inserterしていますか?
NHDaly 2014年

7
@NHDaly:back_inserterの方が速いため
marton78

@ marton78しかし、もしあったとしても、それはごくわずかなマージンで高速化されるべきではないでしょうか?要素を移動する必要がない場合、ベクターではinsertなく呼び出しはpush_backほぼ同じ(O(1))になります。
Felix Dombek、2018年

3
@FelixDombek正解です。それほど遅くなることはありません。v.insert(x, v.end())最初に追加の分岐があります(n個の要素を移動するため、nはゼロです)。ただし、inserter1)を使用すると、push_back2)を使用した場合とは異なる意図が伝達されます。これは異常であり、読者を停止させ、3)は時期尚早な悲観論です。
marton78 2018年

0

2016年には、「単一の引数inserter反復子」を使用するという提案がありました。 https://isocpp.org/files/papers/p0471r0.html。提案が進んだかどうかわかりませんでした。それは理にかなっていると思います。

今のところ、メーカーの機能を定義するこの動作を持つことができます:

template<class Container>
auto sinserter(Container& c){
    using std::end;
    return std::inserter(c, end(c));
}

使用されます:

std::transform(begin(my_vec), end(my_vec), sinserter(my_set), [](auto& e){return e.member;});

これはすべての標準コンテナで機能することを意図していますか?std :: forward_listでは機能しません(コンパイラエラーは、「forward_listにはのインスタンス化内に 'insert'という名前のメンバーがありません」ですinsert_iterator::operator=)。よろしいですか?
ドンハッチ

持って@DonHatch、何もinsert(とend)。そもそも操作forward_listがないようです。そしてそれを変えても終了後は挿入できないと思います。代わりに使用できませんか?insertinsert_afterstd::list
alfC

もちろん、個人的にはstd :: forward_listは必要ありません。しかし、私は一般的な「1つのコンテナーを別のコンテナーにコピーするにはどうすればよいですか?」それが意味をなすすべてのペアのコンテナに対して。私の現在の関心は、@ HowardHinnantのshort_allocなどの汎用コンテナーアロケーターを実行することです。
ドンハッチ

@DonHatch、問題はその質問には多くの変形があるということです。(「「コンテナを別のコンテナにコピーするにはどうすればよいですか?」)。たとえば、元の値を保持しますか、割り当てを最小化しますか?など。最も単純なケースでは、私の意見では、コンストラクタ2回の反復子をとり、コンテナ(ほとんどのコンテナはそれを取ることができます)。 NewContaner new_container(old_other_container.begin(), old_other_container.end())
alfC

1
はい、std :: setはSequentialContainerではありません。それは問題ありません:-) existing_list = std::list(c.begin(), c.end(), existing_list.get_allocator()) とてもいいです。それが私の答えだと思います。乾杯!
ドンハッチ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.