STLのコンテナから要素を削除する


このエントリーをはてなブックマークに追加

STLのコンテナの種類によって、要素の削除の仕方もいろいろ。

vectorの場合

erase-remove idiomと呼ばれるテクニックを使う。このテクニックでは、特定の値に一致する要素を消すときにはerase()とremove()とを、また特定の条件に一致する要素を消すときにはerase()とremove_if()とを組み合わせて使う。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// 値が偶数の時にtrueを返す叙述関数 
bool is_even(int val){
    return !(val % 2);
}

// mapの要素を順番に表示
void printVector( vector<int> &vec ){
    cout << "size = " << vec.size() << endl;
    for(int i = 0; i < vec.size(); ++i){
        cout << vec[i] << ", ";
    }
    cout << endl << endl;
}

int main(void){
    vector<int> vec;
    for(int i = 0; i < 10; ++i){
        vec.push_back(i % 5);
    }

    printVector(vec); // 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 
    // 3に等しい要素をすべて削除
    vec.erase(remove(vec.begin(), vec.end(), 3), vec.end());
    printVector(vec); // 0, 1, 2, 4, 0, 1, 2, 4, 
    // 偶数の要素をすべて削除
    vec.erase(remove_if(vec.begin(), vec.end(), is_even), vec.end());
    printVector(vec); // 1, 1,

    return 0;
}

mapの場合

erase()がメンバ関数で提供されているのでそれを使う。

#include <iostream>
#include <map>
#include <algorithm>

using namespace std;

// vectorの要素を順番に表示
void printMap(map<int, int> &m){
    cout << "size = " << m.size() << endl;
    for(map<int, int>::iterator it = m.begin();
        it != m.end();
        ++it){
        cout << it->first << ", ";
    }
    cout << endl << endl;
}

int main(void){
    map<int, int> m;
    for(int i = 0; i < 10; ++i){
        m[i] = (i * 10);
    }

    printMap(m);
    // keyが3の要素を削除
    m.erase(3);
    printMap(m);

    return 0;
}

vectorの各要素をループで走査しながら削除する場合

vectorの各要素をイテレータを使って走査しつつ、条件に合う要素があればログなどを出力しつつその要素を削除したくなるときがある。そのときはerase()の戻り値をイテレータで受けるという、まず自力では思いつきそうもない方法を使う。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void printVector( vector<int> &vec ){
    cout << "size = " << vec.size() << endl;
    for(int i = 0; i < vec.size(); ++i){
        cout << vec[i] << ", ";
    }
    cout << endl << endl;
}

int main(void){
    vector<int> vec;
    for(int i = 0; i < 10; ++i){
        vec.push_back(i % 5);
    }

    printVector(vec); // 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 
    // forループの3つ目の式はあえて空
    for(vector<int>::iterator it = vec.begin();
        it != vec.end();
        ){
        if (*it == 3){ // 削除条件に合う要素が見つかった
            cout << "val " << *it << " is deleted." << endl;
            it = vec.erase(it); // erase()の戻り値をitで受ける!
        }
        else{
            ++it;
        }
    }
    printVector(vec); // 0, 1, 2, 4, 0, 1, 2, 4, 

    return 0;
}

mapの各要素をループで走査しながら削除する場合

こちらの場合はメンバ関数のerase()が戻り値を戻さないので、少しvectorの場合と形が違う。こちらもトリッキー。

#include <iostream>
#include <map>
#include <algorithm>

using namespace std;

void printMap(map<int, int> &m){
    cout << "size = " << m.size() << endl;
    for(map<int, int>::iterator it = m.begin();
        it != m.end();
        ++it){
        cout << it->first << ", ";
    }
    cout << endl << endl;
}

int main(void){
    map<int, int> m;
    for(int i = 0; i < 10; ++i){
        m[i] = (i * 10);
    }

    printMap(m); // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
    for(map<int, int>::iterator it = m.begin();
        it != m.end();
        ){
        if (it->first == 9){ // 削除条件に合う要素が見つかった
            cout << "key " << it->first << " is deleted." << endl;
            m.erase(it++);
        }
        else{
            ++it;
        }
        
    }
    printMap(m); // 0, 1, 2, 3, 4, 5, 6, 7, 8, 

    return 0;
}

STLはやはり難しい…

参考