要素をstd :: vector <>からインデックスで削除するにはどうすればよいですか?


508

std :: vector <int>があり、n番目の要素を削除したい。それ、どうやったら出来るの?

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

vec.erase(???);

4
両端で挿入と削除を提供するstd :: dequeの使用を検討してください。
ダリオ

40
いいえ、要素を削除したいだけの理由でdequeを使用することを検討しないでください。dequeまたはvectorを使用する理由はたくさんあります。ベクトルから要素を削除することはコストがかかる可能性があることは事実です。特に、ベクトルが大きい場合は、dequeが先ほど投稿したコード例のベクトルよりも優れていると考える理由はありません。
フクロウ2017

6
たとえば、物事をインタラクティブに挿入/削除する物事の「リスト」を表示するグラフィカルアプリケーションがある場合、リストを毎秒50〜100回実行して表示し、物事をいくつか追加/削除することを検討してください。毎分。したがって、「リスト」をベクトルとして実装することは、総合効率の点でおそらくより良いオプションです。
ミシェルビロー

回答:


705

単一の要素を削除するには、次のようにします。

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

// Deletes the second element (vec[1])
vec.erase(vec.begin() + 1);

または、一度に複数の要素を削除するには:

// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin() + 1, vec.begin() + 3);

50
また、バイナリ注意operator+されていない必然のように、他のコンテナ型のイテレータのために定義されたlist<T>::iterator(あなたが行うことができないlist.begin() + 2std::list、あなたが使用する必要がありstd::advance、そのために)
bobobobo

「+1」が最初の要素myVector [0]または実際の位置myVector [1]であると述べていますか
K-SOの毒性が増加しています。

2
事前に、イテレータを変数に保存する必要があります。std :: nextを使用する場合は、1行で実行できます。vec.erase(next(begin(vec)、123));
ダニ

8
回答していただいた皆様、ありがとうございました。要素の削除などの単純な操作でStackOverflowにアクセスする必要がある場合、クラス設計についてどう思いますか?
ピエール

5
@Pierre 特定の要素の数値インデックスはアクセスの主要なモデルではないため、イテレータはそうです。コンテナーの要素を参照するすべての関数は、そのコンテナーのイテレーターを使用します。例:std::find_if
カレス

212

std :: vectorのeraseメソッドはオーバーロードされているので、呼び出す方がおそらく明確です

vec.erase(vec.begin() + index);

単一の要素のみを消去したい場合。


3
しかし、その問題は、要素がいくつあっても発生します。
Zyx 2000

15
要素が1つしかない場合、インデックスは0なので、vec.begin()どちらが有効かがわかります。
Anne Quinn

28
私は誰かがそれvec.erase(0)が機能しないがvec.erase(vec.begin()+0)(または+0なしで)機能しないと述べていたらいいのですが それ以外の場合、一致する関数呼び出しを取得できません。これが私がここに来た理由です
qrtLs '15

@qrtLs vec.erase(0)は、0たまたまnullポインタ定数として解釈された場合、実際にコンパイルされる可能性があります...
LF

57
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
    std::vector<T>::iterator it = vec.begin();
    std::advance(it, pos);
    vec.erase(it);
}

2
マックス、それが機能より優れている理由:template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }私はどちらも優れているとは言っていません。単に個人的な関心を求め、この質問で得られる最良の結果を返すように求めています。

13
@JoeyvG:a vector<T>::iteratorはランダムアクセスイテレータなので、バージョンは問題なく、おそらく少し明確です。ただし、ランダムアクセスイテレータをサポートしていない別のコンテナにコンテナを変更した場合、Maxが投稿したバージョンは問題なく機能するはずです
Lily Ballard

2
これは他のコンテナ形式にも当てはまるので、imoがより良い答えです。std :: next()を使用することもできます。
Bim

コンテナーの内部に依存しないため、はるかに優れたアプローチです。
BartoszKP

std :: advanceは、これがベクトル、つまりリストではないと思われる場合にのみ必要です。しかし、ここで指定したように、operator +は単純ではないでしょうか?このstackoverflow.com/questions/1668088/…によれば、operator +でパフォーマンスが向上する可能性があります
Neil McGill

14

このeraseメソッドは2つの方法で使用されます。

  1. 単一要素の消去:

    vector.erase( vector.begin() + 3 ); // Deleting the fourth element
  2. 要素の範囲を消去:

    vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element

7
これは、受け入れられた回答からほぼ7年後の重複回答です。これを行わないでください。
AlastairG

10

実際、このerase関数は2つのプロファイルで機能します。

  • 単一の要素を削除する

    iterator erase (iterator position);
  • 要素の範囲を削除する

    iterator erase (iterator first, iterator last);

std :: vec.begin()はコンテナの開始をマークしているため、ベクターのi番目の要素を削除する場合は、次のように使用できます。

vec.erase(vec.begin() + index);

よく見ると、vec.begin()はベクトルの開始位置へのポインタにすぎず、それにiの値を追加すると、i位置へのポインタがインクリメントされるため、代わりに次のようにi番目の要素へのポインタにアクセスできます。

&vec[i]

だから私たちは書くことができます:

vec.erase(&vec[i]); // To delete the ith element

6
-1最後の行はコンパイルされません(少なくともVS2017では)。このコードでは、vector :: iteratorはrawポインターから暗黙的に構築可能であると想定していますが、これは標準では必要ありません。
CuriousGeorge

1
これは特にデバッグイテレータに当てはまります
Nishant Singh

9

順序付けられていないベクトルがある場合は、順序付けされていないという事実を利用して、CPPCONでDan Higginsから見たものを使用できます。

template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
    if ( inIndex < inContainer.size() )
    {
        if ( inIndex != inContainer.size() - 1 )
            inContainer[inIndex] = inContainer.back();
        inContainer.pop_back();
        return true;
    }
    return false;
}

リストの順序は関係ないので、リストの最後の要素を取り、それを削除するアイテムの上にコピーし、最後のアイテムをポップして削除します。


ベクトルが順序付けられていない場合、これが最良の答えだと思います。これはiterator + index、そのインデックスでのイテレータの位置を実際に返すという前提に依存していません。これは、すべての反復可能なコンテナに当てはまるわけではありません。また、バックポインターを利用することで、線形ではなく一定の複雑さも実現します。
theferrit32 2018年

1
これは全くとSTDのlibに追加する必要がありますunordered_removeし、unordered_remove_ifそれがされていると私はそれを逃した場合を除き、これらの日より多くの頻繁に起こっているれ、... :)
ウィル・クロフォード

コピー割り当ての代わりに移動割り当てまたはスワップの使用を提案する場合。
Carsten S

std::remove並べ替える削除するすべての要素が最後であるので、そのコンテナ、あなたがC ++ 17を使用している場合は、次のように手動でそれを行うには必要はありません
キース・

@keithどのようにstd::remove役立ちますか?cppreferenceは、C ++ 17でも、すべてのremoveオーバーロードには述語が必要であり、インデックスを取得するものはないと主張しています。
ポールデュボワ

4

大きなベクトル(サイズ> 100,000)で作業していて、たくさんの要素を削除したい場合は、次のようにすることをお勧めします。

int main(int argc, char** argv) {

    vector <int> vec;
    vector <int> vec2;

    for (int i = 0; i < 20000000; i++){
        vec.push_back(i);}

    for (int i = 0; i < vec.size(); i++)
    {
        if(vec.at(i) %3 != 0)
            vec2.push_back(i);
    }

    vec = vec2;
    cout << vec.size() << endl;
}

このコードは、3で割り切れないvec内のすべての数値を取り、それをvec2にコピーします。その後、vec2をvecにコピーします。かなり速いです。20,000,000の要素を処理するために、このアルゴリズムは0.8秒しかかかりません!

消去方法でも同じことを行いましたが、それには非常に時間がかかりました。

Erase-Version (10k elements)  : 0.04 sec
Erase-Version (100k elements) : 0.6  sec
Erase-Version (1000k elements): 56   sec
Erase-Version (10000k elements): ...still calculating (>30 min)

6
これはどのように質問に答えますか?
Regis Portalez 2016年

4
興味深いですが、質問には関係ありません。
Roddy

インプレースアルゴリズムの方が高速ではありませんか?
user202729

2
それはstd :: remove_if(+ erase)です
RiaD


3

私はそれがあなたが探しているものだと思うので、これを読むことをお勧めします。https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom

たとえば使用する場合

 vec.erase(vec.begin() + 1, vec.begin() + 3);

ベクトルのn番目の要素を消去しますが、2番目の要素を消去すると、ベクトルの他のすべての要素がシフトされ、ベクトルのサイズが-1になります。ベクトルsize()が減少しているため、ベクトルをループする場合、これは問題になる可能性があります。この提供されたリンクのような問題がある場合は、標準C ++ライブラリの既存のアルゴリズムを使用することをお勧めします。および「remove」または「remove_if」。

これが役に立てば幸い


0

上記の回答では、常に署名付きインデックスがあると想定しています。悲しいことに、索引付けにstd::vector使用size_typeし、difference_typeイテレータの計算「-Wconversion」とフレンドが有効になっている場合、これらは一緒に機能しません。これは、署名付きと署名なしの両方を処理できる一方で、質問に答える別の方法です。

削除する:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
    v.erase(iter);
}

取る:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);

    auto val = *iter;
    v.erase(iter);

    return val;
}

0

これを行うには、ベクター内の値を使用して要素を削除する場合にこれを実行するもう1つの方法があります。これは、ベクター上で実行するだけです。

vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));

ここから値が削除されます。ありがとう


0

これはどう?

void squeeze(vector<int> &v)
{
    int j = 0;
    for (int i = 1; i < v.size(); i++)
        if (v[i] != v[j] && ++j != i)
            v[j] = v[i];
    v.resize(j + 1);
}

-4

最速の方法(時間によるプログラミングコンテストの複雑さ()=定数)

1秒で100Mのアイテムを消去できます。

    vector<int> it = (vector<int>::iterator) &vec[pos];
    vec.erase(it);

そして最も読みやすい方法: vec.erase(vec.begin() + pos);


2
これは非常に移植性がありません。libstdc ++では機能しますが、libc ++では機能せず、MSVCでは機能しません。 vector<int>::iterator必ずしも同じではありませんint *
Marshall Clow

2
それはうんざりです、私はlibstdc ++を変更して動作しないようにすると思います。
Jonathan Wakely
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.