vector

[C++] vector::erase()の使い方 – 指定した値を削除する

C++のstd::vector::erase()は、指定した位置または範囲の要素を削除するメンバ関数です。

特定の値を削除するには、std::remove()と組み合わせて使用します。

std::remove()は削除対象を末尾に移動し、新しい末尾のイテレータを返すため、erase()でその範囲を削除します。

例として、vec.erase(std::remove(vec.begin(), vec.end(), value), vec.end());のように記述します。

vector::erase()とは

vector::erase()は、C++の標準ライブラリである<vector>に含まれるメンバ関数で、std::vectorコンテナから要素を削除するために使用されます。

この関数は、指定した位置にある要素を削除することができ、また、特定の範囲内の要素を一度に削除することも可能です。

vector::erase()を使用することで、動的配列であるstd::vectorのサイズを変更し、不要な要素を取り除くことができます。

これにより、メモリの効率的な管理や、データの整合性を保つことができます。

以下に、vector::erase()の基本的な使い方を示すサンプルコードを示します。

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    // 3を削除する
    numbers.erase(numbers.begin() + 2); // 0-based index
    // 結果を表示
    for (int num : numbers) {
        std::cout << num << " "; // 削除後の要素を表示
    }
    std::cout << std::endl; // 改行
    return 0;
}
1 2 4 5

このコードでは、std::vectorに整数のリストを作成し、erase()を使って3を削除しています。

erase()は、削除したい要素の位置を指定することで、その要素を取り除きます。

vector::erase()の基本的な使い方

vector::erase()を使用する際の基本的な構文は以下の通りです。

iterator erase(iterator position);
iterator erase(iterator first, iterator last);
  • position: 削除したい要素の位置を指すイテレータ。
  • first, last: 削除したい範囲の開始と終了を指すイテレータ。

firstは含まれ、lastは含まれません。

1. 単一要素の削除

特定の位置にある単一の要素を削除する場合、次のようにします。

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {10, 20, 30, 40, 50};
    // 20を削除する
    numbers.erase(numbers.begin() + 1); // 0-based index
    // 結果を表示
    for (int num : numbers) {
        std::cout << num << " "; // 削除後の要素を表示
    }
    std::cout << std::endl; // 改行
    return 0;
}
10 30 40 50

このコードでは、std::vectorから20を削除しています。

erase()numbers.begin() + 1を渡すことで、2番目の要素を指定しています。

2. 範囲の削除

複数の要素を一度に削除する場合は、次のように範囲を指定します。

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    // 3から6までの要素を削除する
    numbers.erase(numbers.begin() + 2, numbers.begin() + 6); // 3, 4, 5, 6を削除
    // 結果を表示
    for (int num : numbers) {
        std::cout << num << " "; // 削除後の要素を表示
    }
    std::cout << std::endl; // 改行
    return 0;
}
1 2 7 8 9

この例では、3から6までの要素を削除しています。

erase()に範囲を指定することで、複数の要素を一度に取り除くことができます。

3. 注意点

  • erase()を使用すると、削除された要素の後ろにある要素が前に詰められます。

そのため、削除後のstd::vectorのサイズが変更されることに注意が必要です。

  • 削除した要素の後のイテレータは無効になりますので、削除後に再度イテレータを使用する場合は、再取得が必要です。

指定した値を削除する方法

std::vectorから特定の値を削除するためには、std::removevector::erase()を組み合わせて使用します。

std::removeは、指定した値を持つ要素を末尾に移動させ、削除対象の要素を新しい末尾の位置に移動します。

その後、erase()を使って実際に要素を削除します。

1. 指定した値を削除する基本的な方法

以下のサンプルコードでは、std::vectorから特定の値を削除する方法を示します。

#include <iostream>
#include <vector>
#include <algorithm> // std::removeを使用するために必要
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 3, 5, 3};
    // 値3を削除する
    numbers.erase(std::remove(numbers.begin(), numbers.end(), 3), numbers.end());
    // 結果を表示
    for (int num : numbers) {
        std::cout << num << " "; // 削除後の要素を表示
    }
    std::cout << std::endl; // 改行
    return 0;
}
1 2 4 5

このコードでは、std::removeを使って値3を持つ要素を末尾に移動させ、その後erase()で実際に削除しています。

これにより、std::vectorからすべての3が取り除かれます。

2. 複数の値を削除する方法

複数の異なる値を削除したい場合は、std::removeを複数回呼び出すか、ループを使用して削除することができます。

以下の例では、値3と値4を削除します。

#include <iostream>
#include <vector>
#include <algorithm> // std::removeを使用するために必要
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 3, 5, 4, 3};
    // 値3を削除
    numbers.erase(std::remove(numbers.begin(), numbers.end(), 3), numbers.end());
    // 値4を削除
    numbers.erase(std::remove(numbers.begin(), numbers.end(), 4), numbers.end());
    // 結果を表示
    for (int num : numbers) {
        std::cout << num << " "; // 削除後の要素を表示
    }
    std::cout << std::endl; // 改行
    return 0;
}
1 2 5

この例では、まず値3を削除し、その後値4を削除しています。

std::removeerase()を組み合わせることで、指定した値を効率的に削除することができます。

3. 注意点

  • std::removeは、実際には要素を削除するのではなく、削除対象の要素を末尾に移動させるだけです。

そのため、必ずerase()を呼び出して、実際に要素を削除する必要があります。

  • std::removeは、削除したい値が存在しない場合でも、元のstd::vectorのサイズは変わりません。

vector::erase()を使う際の注意点

vector::erase()を使用する際には、いくつかの注意点があります。

これらを理解しておくことで、意図しない動作を避け、効率的にプログラムを作成することができます。

以下に主な注意点を挙げます。

1. イテレータの無効化

erase()を呼び出すと、削除された要素の後にあるすべての要素のイテレータが無効になります。

これにより、削除後にこれらのイテレータを使用すると未定義の動作を引き起こす可能性があります。

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    auto it = numbers.begin() + 2; // 3を指すイテレータ
    numbers.erase(it); // 3を削除
    // itは無効になっているため、使用しない方が良い
    // std::cout << *it; // これは未定義の動作を引き起こす
    return 0;
}

2. サイズの変更

erase()を使用すると、std::vectorのサイズが変更されます。

これにより、ループや他の処理でサイズを前提にしている場合、意図しない結果を招くことがあります。

特に、ループ内で要素を削除する場合は注意が必要です。

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    for (size_t i = 0; i < numbers.size(); ++i) {
        if (numbers[i] % 2 == 0) {
            numbers.erase(numbers.begin() + i); // 偶数を削除
            // iをインクリメントすると、次の要素がスキップされる
        }
    }
    // 結果を表示
    for (int num : numbers) {
        std::cout << num << " "; // 1 3
    }
    std::cout << std::endl; // 改行
    return 0;
}

このコードでは、偶数を削除する際にインデックスを手動で管理しているため、次の要素がスキップされてしまいます。

ループの条件を見直す必要があります。

3. 複数回の呼び出し

erase()を複数回呼び出す場合、毎回新しいイテレータを取得する必要があります。

これを怠ると、無効なイテレータを使用してしまう可能性があります。

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    // 1を削除
    numbers.erase(numbers.begin()); // 1を削除
    // 2を削除
    // numbers.erase(numbers.begin()); // ここで無効なイテレータを使用してしまう
    // 正しい方法
    numbers.erase(numbers.begin()); // 2を削除
    // 結果を表示
    for (int num : numbers) {
        std::cout << num << " "; // 3 4 5
    }
    std::cout << std::endl; // 改行
    return 0;
}

4. 空のベクターに対する操作

空のstd::vectorに対してerase()を呼び出すと、未定義の動作を引き起こす可能性があります。

操作を行う前に、std::vectorが空でないことを確認することが重要です。

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers; // 空のベクター
    // numbers.erase(numbers.begin()); // これは未定義の動作を引き起こす
    if (!numbers.empty()) {
        numbers.erase(numbers.begin()); // 空でない場合のみ削除
    }
    return 0;
}

これらの注意点を理解し、適切に対処することで、vector::erase()を安全かつ効果的に使用することができます。

応用的な使い方

vector::erase()は、基本的な要素削除だけでなく、さまざまな応用的な使い方が可能です。

ここでは、いくつかの応用例を紹介します。

1. 条件に基づく要素の削除

特定の条件に基づいて要素を削除する場合、std::remove_iferase()を組み合わせることができます。

以下の例では、偶数の要素を削除します。

#include <iostream>
#include <vector>
#include <algorithm> // std::remove_ifを使用するために必要
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    // 偶数を削除する
    numbers.erase(std::remove_if(numbers.begin(), numbers.end(), [](int num) {
        return num % 2 == 0; // 偶数の場合にtrueを返す
    }), numbers.end());
    // 結果を表示
    for (int num : numbers) {
        std::cout << num << " "; // 削除後の要素を表示
    }
    std::cout << std::endl; // 改行
    return 0;
}
1 3 5 7 9

このコードでは、ラムダ式を使用して偶数を削除しています。

std::remove_ifは条件に合致する要素を末尾に移動させ、その後erase()で削除します。

2. 複数の異なる値を一度に削除

複数の異なる値を一度に削除する場合、std::remove_ifを使用して条件を指定することができます。

以下の例では、値3と値5を削除します。

#include <iostream>
#include <vector>
#include <algorithm> // std::remove_ifを使用するために必要
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 3, 7, 5};
    // 値3または5を削除する
    numbers.erase(std::remove_if(numbers.begin(), numbers.end(), [](int num) {
        return num == 3 || num == 5; // 3または5の場合にtrueを返す
    }), numbers.end());
    // 結果を表示
    for (int num : numbers) {
        std::cout << num << " "; // 削除後の要素を表示
    }
    std::cout << std::endl; // 改行
    return 0;
}
1 2 4 6 7

この例では、条件に基づいて複数の値を一度に削除しています。

ラムダ式を使うことで、柔軟に条件を指定できます。

3. 逆順での削除

要素を削除する際に、逆順で削除することで、インデックスのずれを防ぐことができます。

以下の例では、偶数を逆順で削除します。

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    // 逆順で偶数を削除する
    for (int i = numbers.size() - 1; i >= 0; --i) {
        if (numbers[i] % 2 == 0) {
            numbers.erase(numbers.begin() + i); // 偶数を削除
        }
    }
    // 結果を表示
    for (int num : numbers) {
        std::cout << num << " "; // 削除後の要素を表示
    }
    std::cout << std::endl; // 改行
    return 0;
}
1 3 5 7 9

この方法では、逆順でループを回すことで、削除後のインデックスのずれを防ぎ、正しく要素を削除することができます。

4. 複数のベクターからの要素削除

複数のstd::vectorから特定の要素を削除する場合、std::setを使用して削除対象の値を管理することができます。

以下の例では、2つのベクターから共通の値を削除します。

#include <iostream>
#include <vector>
#include <set>
#include <algorithm> // std::removeを使用するために必要
int main() {
    std::vector<int> vec1 = {1, 2, 3, 4, 5};
    std::vector<int> vec2 = {3, 4, 5, 6, 7};
    // vec2の要素をsetに格納
    std::set<int> toRemove(vec2.begin(), vec2.end());
    // vec1からtoRemoveに含まれる要素を削除
    vec1.erase(std::remove_if(vec1.begin(), vec1.end(), [&](int num) {
        return toRemove.count(num) > 0; // vec2に含まれる場合にtrueを返す
    }), vec1.end());
    // 結果を表示
    for (int num : vec1) {
        std::cout << num << " "; // 削除後の要素を表示
    }
    std::cout << std::endl; // 改行
    return 0;
}
1 2

この例では、std::setを使用して、vec2に含まれる要素をvec1から削除しています。

これにより、効率的に共通の要素を取り除くことができます。

これらの応用的な使い方を活用することで、vector::erase()をより効果的に利用し、柔軟なデータ操作が可能になります。

まとめ

この記事では、C++のvector::erase()の使い方や注意点、応用的な利用方法について詳しく解説しました。

特に、要素の削除に関する基本的な操作から、条件に基づく削除や複数のベクターからの要素削除まで、さまざまなテクニックを紹介しました。

これらの知識を活用して、より効率的にデータを管理し、プログラムの品質を向上させることができるでしょう。

ぜひ、実際のプロジェクトや練習問題に取り入れて、vector::erase()の活用方法を試してみてください。

関連記事

Back to top button