私はstl vectorのAPIドキュメントを見ていて、vectorクラスに特定の値を持つ要素の削除を許可するメソッドがないことに気付きました。これは一般的な操作のようであり、これを行うための組み込みの方法がないのは奇妙に思われます。
私はstl vectorのAPIドキュメントを見ていて、vectorクラスに特定の値を持つ要素の削除を許可するメソッドがないことに気付きました。これは一般的な操作のようであり、これを行うための組み込みの方法がないのは奇妙に思われます。
回答:
std::remove
コンテナから実際に要素を消去するわけではありませんcontainer_type::erase
が、現在コンテナの最後にある余分な要素を実際に削除するために渡すことができる新しい終了イテレータを返します。
std::vector<int> vec;
// .. put in some values ..
int int_to_remove = n;
vec.erase(std::remove(vec.begin(), vec.end(), int_to_remove), vec.end());
vec.end()
、呼び出しのどちらの側でも同じであることが保証されていstd::remove
ますか?このようにWebの他の部分を読むことは私には安全だと思われますが、それは明確に述べられるべきです。
vec.end()
同じである必要はありません。正確である必要があります(それが正しい)。
vec.end()
同じである必要はありstd::remove
ませんが、変更しないので問題ありません。変更した場合(および古い値が無効になる場合)、問題が発生します。パラメーターの評価順序が指定されていないため、2番目のパラメーターがvec.end()
使用されるまでに2番目のパラメーターがまだ有効かどうかがわかりません。同じ理由は単純std::remove
で、コンテナのサイズを変更せず、コンテンツを移動するだけです。
std::remove
1つの引数しか取りません。それはconst char *_Filename
です。どのメソッドを呼び出す必要がありますか?
remove
ファイルを削除するバージョンです。コンテナを扱う<algorithm>
のバージョンにアクセスするには、を含める必要がありますremove
。
アイテムを削除する場合は、次の方が効率的です。
std::vector<int> v;
auto it = std::find(v.begin(), v.end(), 5);
if(it != v.end())
v.erase(it);
または、順序が関係ない場合は、アイテムを移動するオーバーヘッドを回避できます。
std::vector<int> v;
auto it = std::find(v.begin(), v.end(), 5);
if (it != v.end()) {
using std::swap;
// swap the one to be removed with the last element
// and remove the item at the end of the container
// to prevent moving all items after '5' by one
swap(*it, v.back());
v.pop_back();
}
グローバルメソッドstd :: removeを開始イテレータと終了イテレータで使用し、次にstd :: vector.eraseを使用して要素を実際に削除します。
ドキュメントのリンク
std :: remove http://www.cppreference.com/cppalgorithm/remove.html
std :: vector.erase http://www.cppreference.com/cppvector/erase.html
std::vector<int> v;
v.push_back(1);
v.push_back(2);
//Vector should contain the elements 1, 2
//Find new end iterator
std::vector<int>::iterator newEnd = std::remove(v.begin(), v.end(), 1);
//Erase the "removed" elements.
v.erase(newEnd, v.end());
//Vector should now only contain 2
エラーを指摘してくれたJim Buckに感謝します。
より短い解決策(ベクター名を4回繰り返すことを強制しない)は、Boostを使用することです。
#include <boost/range/algorithm_ext/erase.hpp>
// ...
boost::remove_erase(vec, int_to_remove);
http://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/range/reference/algorithms/new/remove_erase.htmlを参照してください
c ++ 20から:
非メンバー関数が導入されましたstd::erase
。これは、削除するベクトルと値を入力として受け取ります。
例:
std::vector<int> v = {90,80,70,60,50};
std::erase(v,50);
map::erase
!
述語を使用できるようにstd :: remove_ifも参照してください...
上記のリンクの例を次に示します。
vector<int> V;
V.push_back(1);
V.push_back(4);
V.push_back(2);
V.push_back(8);
V.push_back(5);
V.push_back(7);
copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
// The output is "1 4 2 8 5 7"
vector<int>::iterator new_end =
remove_if(V.begin(), V.end(),
compose1(bind2nd(equal_to<int>(), 0),
bind2nd(modulus<int>(), 2)));
V.erase(new_end, V.end()); [1]
copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
// The output is "1 5 7".
追加のインクルードなしでそれをしたい場合:
vector<IComponent*> myComponents; //assume it has items in it already.
void RemoveComponent(IComponent* componentToRemove)
{
IComponent* juggler;
if (componentToRemove != NULL)
{
for (int currComponentIndex = 0; currComponentIndex < myComponents.size(); currComponentIndex++)
{
if (componentToRemove == myComponents[currComponentIndex])
{
//Since we don't care about order, swap with the last element, then delete it.
juggler = myComponents[currComponentIndex];
myComponents[currComponentIndex] = myComponents[myComponents.size() - 1];
myComponents[myComponents.size() - 1] = juggler;
//Remove it from memory and let the vector know too.
myComponents.pop_back();
delete juggler;
}
}
}
}
特にアイテムを消去するために使用できる方法は2つあります。ベクトルを取ることができます
std :: vector < int > v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(40);
v.push_back(50);
1)非効率的な方法:非常に効率的であるように見えますが、消去関数が要素を削除し、すべての要素を1 だけ左にシフトするため、そうではありません。 そのため、その複雑さはO(n ^ 2)になります。
std :: vector < int > :: iterator itr = v.begin();
int value = 40;
while ( itr != v.end() )
{
if(*itr == value)
{
v.erase(itr);
}
else
++itr;
}
2)効率的な方法(推奨):ERASE-REMOVEイディオムとも呼ばれます。
削除アルゴリズムの出力は次のとおりです。
10 20 30 50 40 50
removeの戻り値の型は、その範囲の新しい終わりへの反復子であるためです。
template <class ForwardIterator, class T>
ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val);
次に、ベクターの消去機能を使用して、ベクターの新しい端から古い端までの要素を削除します。O(1)時間必要です。
v.erase ( std :: remove (v.begin() , v.end() , element ) , v.end () );
したがって、このメソッドはO(n)で機能します
*
C ++コミュニティはあなたのリクエストを聞いています:)
*
C ++ 20は、今それを行う簡単な方法を提供します。それは次のように簡単になります:
#include <vector>
...
vector<int> cnt{5, 0, 2, 8, 0, 7};
std::erase(cnt, 0);
std :: eraseとstd :: erase_ifをチェックアウトする必要があります。
値のすべての要素(ここでは「0」)を削除するだけでなく、O(n)時間の複雑さで削除します。あなたが得ることができる最高のものはどれですか。
コンパイラがC ++ 20をサポートしていない場合は、erase-removeイディオムを使用する必要があります。
#include <algorithm>
...
vec.erase(std::remove(vec.begin(), vec.end(), 0), vec.end());