範囲の要素の削除・重複削除 (C++03, C++20)

C++

範囲の要素を削除・重複削除する関数の説明です。

概要

配列やコンテナの要素の変更を行えます。
範囲はシーケンシャルアクセスが必要です。
範囲の指定方法は、
・std::xxx(C++03): 対象の範囲 [first, last) のイテレータ―を指定します。
・std::ranges::xxx(C++20): 対象の範囲 [first, last) のイテレータ―を指定します。
・std::ranges::xxx(C++20): 対象の範囲を直接指定します。
条件判定や、値生成に関数を指定するものがあります。※
std::ranges::xxx(C++20): 射影(projection)関数を指定できるものがあります。※
出力先は、既存の範囲に上書きするものと、別途出力先のイテレーターを指定するものがあります。※
※詳細についてはこちらを参照してください。https://mappuri.com/program/cpp20-algorithm/

要素の削除

remove

指定した値の要素を削除します。
std::ranges::xxx(C++20): 射影(projection)関数を指定できます。
削除された後ろの要素の値は前に詰めれらます。残った範囲は切り詰められず、範囲のサイズは変更されません。戻り値でこの位置や範囲を返すので、必要に応じて erase 関数などで消去します。

remove_if

指定した条件の要素を削除します。
条件判定の関数を指定します。
std::ranges::xxx(C++20): 射影(projection)関数を指定できます。
削除された後ろの要素の値は前に詰めれらます。残った範囲は切り詰められず、範囲のサイズは変更されません。戻り値でこの位置や範囲を返すので、必要に応じて erase 関数などで消去します。

remove_copy

指定した要素を削除して出力します。
出力先のイテレーターを指定します。
std::ranges::xxx(C++20): 射影(projection)関数を指定できます。

remove_copy_if

指定した要素を削除して出力します。
出力先のイテレーターを指定します。
条件判定の関数を指定します。
std::ranges::xxx(C++20): 射影(projection)関数を指定できます。

remove, … のサンプル (C++03)

#include <iostream>

/** r 内の [first, last) の範囲と値を出力 範囲:[0, 9) 値:1 2 3 4 5 4 5 6 6 */
template<class T, class U, class V>
static void output(T&& r, U&& first, V&& last) {
	std::cout << "範囲:[" << std::distance(std::begin(r), first) << ", " << std::distance(std::begin(r), last) << ")";
	std::cout << " 値:";
	std::string delim = "";
	for (auto i = first; i != last; ++i, delim = ", ") {
		std::cout << delim << *i;
	}
	std::cout << std::endl;
}

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

int main(int argc, char* argv[]) {
	{
		// 指定した値の要素を削除します。(C++03)
		std::vector<int> r = { 1, 2, 3, 4, 5 };
		auto remove = std::remove(r.begin(), r.end(), 3);
		output(r, r.begin(), remove); // 範囲:[0, 4) 値:1, 2, 4, 5 <- 削除後範囲
		output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 2, 4, 5, 5 <- 全体
		// 削除後範囲に切り詰める(以降同様)
		r.erase(remove, r.end());
		output(r, r.begin(), r.end()); // 範囲:[0, 4) 値:1, 2, 4, 5 <- 全体
	}
	{
		// 指定した条件の要素を削除します。(C++03)
		std::vector<int> r = { 1, 2, 3, 4, 5 };
		auto remove_if = std::remove_if(r.begin(), r.end(), [](int x) { return x & 1; }); // 奇数
		output(r, r.begin(), remove_if); // 範囲:[0, 2) 値:2, 4
	}
	{
		// 指定した要素を削除して出力します。(C++03)
		std::vector<int> r = { 1, 2, 3, 4, 5 };
		std::vector<int> o(r.size());
		auto remove_copy = std::remove_copy(r.begin(), r.end(), o.begin(), 3);
		output(o, o.begin(), remove_copy); // 範囲:[0, 4) 値:1, 2, 4, 5
	}
	{
		// 指定した条件の要素を削除して出力します。(C++03)
		std::vector<int> r = { 1, 2, 3, 4, 5 };
		std::vector<int> o(r.size());
		auto remove_copy_if = std::remove_copy_if(r.begin(), r.end(), o.begin(), [](int x) { return x & 1; }); // 奇数
		output(o, o.begin(), remove_copy_if); // 範囲:[0, 2) 値:2, 4
	}
	return 0;
}

remove, … のサンプル (C++20 range)

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

int main(int argc, char* argv[]) {
	{
		// 指定した値の要素を削除します。(C++20, range)
		std::vector<int> r = { 1, 2, 3, 4, 5 };
		auto remove = std::ranges::remove(r, 3);
		output(r, r.begin(), remove.begin()); // 範囲:[0, 4) 値:1, 2, 4, 5 <- 削除後範囲
		output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 2, 4, 5, 5 <- 全体
		// 削除後範囲に切り詰める(以降同様)
		r.erase(remove.begin(), remove.end());
		output(r, r.begin(), r.end()); // 範囲:[0, 4) 値:1, 2, 4, 5 <- 全体
	}
	{
		// 指定した条件の要素を削除します。(C++20, range)
		std::vector<int> r = { 1, 2, 3, 4, 5 };
		auto remove_if = std::ranges::remove_if(r, [](int x) { return x & 1; }); // 奇数
		output(r, r.begin(), remove_if.begin()); // 範囲:[0, 2) 値:2, 4
	}
	{
		// 指定した要素を削除して出力します。(C++20, range)
		std::vector<int> r = { 1, 2, 3, 4, 5 };
		std::vector<int> o(r.size());
		auto remove_copy = std::ranges::remove_copy(r, o.begin(), 3);
		output(o, o.begin(), remove_copy.out); // 範囲:[0, 4) 値:1, 2, 4, 5
	}
	{
		// 指定した条件の要素を削除して出力します。(C++20, range)
		std::vector<int> r = { 1, 2, 3, 4, 5 };
		std::vector<int> o(r.size());
		auto remove_copy_if = std::ranges::remove_copy_if(r, o.begin(), [](int x) { return x & 1; }); // 奇数
		output(o, o.begin(), remove_copy_if.out); // 範囲:[0, 2) 値:2, 4
	}
	return 0;
}

隣り合う重複要素の削除

unique

隣り合う重複する要素を削除します。
必要に応じて条件判定の関数を指定できます。
std::ranges::xxx(C++20): 射影(projection)関数を指定できます。
離れた位置にある重複する要素は削除されません。必要に応じてあらかじめ sort 関数などでソートしておきます。
削除された後ろの要素の値は前に詰めれらます。残った範囲は切り詰められず、範囲のサイズは変更されません。戻り値でこの位置や範囲を返すので、必要に応じて erase 関数などで消去します。

unique_copy

隣り合う重複要素を削除して出力します。
出力先のイテレーターを指定します。
必要に応じて条件判定の関数を指定できます。
std::ranges::xxx(C++20): 射影(projection)関数を指定できます。
離れた位置にある重複する要素は削除されません。必要に応じてあらかじめ sort 関数などでソートしておきます。

unique, unique_copy のサンプル (C++03)

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

int main(int argc, char* argv[]) {
	{
		// 隣り合う重複する要素を削除します。(C++03)
		std::vector<int> r = { 1, 2, 2, 4, 2, 2, 5 };
		auto unique = std::unique(r.begin(), r.end());
		output(r, r.begin(), unique); // 範囲:[0, 5) 値:1, 2, 4, 2, 5 <- 削除後範囲
		output(r, r.begin(), r.end()); // 範囲:[0, 7) 値:1, 2, 4, 2, 5, 2, 5 <- 全体
		// 削除後範囲に切り詰める(以降同様)
		r.erase(unique, r.end());
		output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 2, 4, 2, 5 <- 全体
	}
	{
		// 隣り合う指定した条件で重複する要素を削除します。(C++03)
		std::vector<int> r = { 11, 21, 22, 41, 21, 22, 51 };
		auto unique = std::unique(r.begin(), r.end(),
			[](int x, int y) { return x / 10 == y / 10; }); // 10の位で比較
		output(r, r.begin(), unique); // 範囲:[0, 5) 値:11, 21, 41, 21, 51
	}
	{
		// 隣り合う重複要素を削除して出力します。(C++03)
		std::vector<int> r = { 1, 2, 2, 4, 2, 2, 5 };
		std::vector<int> o(r.size());
		auto unique_copy = std::unique_copy(r.begin(), r.end(), o.begin());
		output(o, o.begin(), unique_copy); // 範囲:[0, 5) 値:1, 2, 4, 2, 5
	}
	{
		// 隣り合う指定した条件で重複する要素を削除して出力します。(C++03)
		std::vector<int> r = { 11, 21, 22, 41, 21, 22, 51 };
		std::vector<int> o(r.size());
		auto unique_copy = std::unique_copy(r.begin(), r.end(), o.begin(),
			[](int x, int y) { return x / 10 == y / 10; }); // 10の位で比較
		output(o, o.begin(), unique_copy); // 範囲:[0, 5) 値:11, 21, 41, 21, 51
	}
	return 0;
}

unique, unique_copy のサンプル (C++20 range)

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

int main(int argc, char* argv[]) {
	{
		// 隣り合う重複する要素を削除します。(C++20, range)
		std::vector<int> r = { 1, 2, 2, 4, 2, 2, 5 };
		auto unique = std::ranges::unique(r);
		output(r, r.begin(), unique.begin()); // 範囲:[0, 5) 値:1, 2, 4, 2, 5 <- 削除後範囲
		output(r, r.begin(), r.end()); // 範囲:[0, 7) 値:1, 2, 4, 2, 5, 2, 5 <- 全体
		// 削除後範囲に切り詰める(以降同様)
		r.erase(unique.begin(), unique.end());
		output(r, r.begin(), r.end()); // 範囲:[0, 5) 値:1, 2, 4, 2, 5 <- 全体
	}
	{
		// 隣り合う指定した条件で重複する要素を削除します。(C++20, range)
		std::vector<int> r = { 11, 21, 22, 41, 21, 22, 51 };
		auto unique = std::ranges::unique(r,
			[](int x, int y) { return x / 10 == y / 10; }); // 10の位で比較
		output(r, r.begin(), unique.begin()); // 範囲:[0, 5) 値:11, 21, 41, 21, 51
	}
	{
		// 隣り合う重複要素を削除して出力します。(C++20, range)
		std::vector<int> r = { 1, 2, 2, 4, 2, 2, 5 };
		std::vector<int> o(r.size());
		auto unique_copy = std::ranges::unique_copy(r, o.begin());
		output(o, o.begin(), unique_copy.out); // 範囲:[0, 5) 値:1, 2, 4, 2, 5
	}
	{
		// 隣り合う指定した条件で重複する要素を削除して出力します。(C++20, range)
		std::vector<int> r = { 11, 21, 22, 41, 21, 22, 51 };
		std::vector<int> o(r.size());
		auto unique_copy = std::ranges::unique_copy(r, o.begin(),
			[](int x, int y) { return x / 10 == y / 10; }); // 10の位で比較
		output(o, o.begin(), unique_copy.out); // 範囲:[0, 5) 値:11, 21, 41, 21, 51
	}
	return 0;
}

コメント

タイトルとURLをコピーしました