[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::remove
とvector::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::remove
とerase()
を組み合わせることで、指定した値を効率的に削除することができます。
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_if
とerase()
を組み合わせることができます。
以下の例では、偶数の要素を削除します。
#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()
の活用方法を試してみてください。