範囲同士の比較(前方一致) equal, mismatch, lexicographical_compare (C++03/C++20)

C++

コレクション同士を先頭から比較する関数の説明です。

概要

2つの範囲の要素はソート済みの必要があります。
要素はシーケンシャルアクセスが必要です。一部でランダムアクセスがないと計算量が大きくなります。
コレクションの指定方法は基本的に以下の通りですが、例外があるので個別の関数を参照してください。
・std::xxx: 対象の範囲 [first, last) のイテレータ―を指定します。(C++14)
・・範囲2の last を省略した場合は、範囲1の大きさと同じ範囲が対象になります。(C++03)
・std::ranges::xxx(C++20): 対象の範囲 [first, last) のイテレータ―を指定します。
・・範囲2の last を省略した場合は、範囲1の大きさと同じ範囲が対象になります。
・std::ranges::xxx(C++20): 対象の範囲を直接指定します。
比較関数は関数ごとに異なります。
詳細についてはこちらを参照してください。https://mappuri.com/program/cpp20-algorithm/

関数の説明

equal

2つの範囲が等しいか比較します。
r2 の last を省略した場合は、r1 の大きさと同じ範囲が対象になります。(C++03)
r2 の last を指定した場合、r1, r2 の大きさの比較が行われます。その場合ランダムアクセス可能でないと計算量が大きくなります。(C++14)
比較関数には、等しい(==)ときに true を返す関数を指定します。

mismatch

2つの範囲が等しくない位置を検索します。
r2 の last を省略した場合は、r1 の大きさと同じ範囲が対象になります。(C++03)
r2 の last を指定するには C++14 以上が必要です。(C++14)
比較関数には、要素が等しい(==)ときに true を返す関数を指定します。
一致しなかった位置、または終端を返します。

lexicographical_compare

r1 が r2 より辞書的に小さいか比較します。
比較関数には、要素がより小さい(<)ときに true を返す関数を指定します。
r1 が r2 より小さいときに true を返します。

lexicographical_compare_three_way

r1 と r2 を辞書的に三方比較します。
C++20 の std::lexicographical_compare_three_way イテレーター版しかありません。
比較関数には、三方比較(<=>)結果を返す関数を指定します。
r1 と r2 の三方比較結果を返します。

サンプルプログラム

C++03/14/20 イテレーター指定
#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 << " 値:";
	for (auto i = first; i != last; ++i) {
		std::cout << *i << " ";
	}
	std::cout << std::endl;
}

/** r 内の it の位置と値を出力 位置:2 値:3 */
template<class T, class U>
static void output(T&& r, U&& it) {
	std::cout << "位置:" << std::distance(std::begin(r), it);
	std::cout << " 値:";
	if (it == std::end(r) || &*it == nullptr) {
		std::cout << "end";
	} else {
		std::cout << *it;
	}
	std::cout << std::endl;
}

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

int main(int argc, char* argv[]) {
	std::vector<int> r1 = { 1, 2, 3, 4, 5 };
	std::vector<int> r2 = { 1, 2, 3, 4, 5, 6 };

	// 2つの範囲が等しいか比較します。
	auto equal = std::equal(r1.begin(), r1.end(), r2.begin());
	std::cout << std::boolalpha << equal << std::endl;
	// true

	// 2つの範囲が等しいか比較します。(C++14)
	auto equal2 = std::equal(r1.begin(), r1.end(), r2.begin(), r2.end());
	std::cout << std::boolalpha << equal2 << std::endl;
	// false

	// 比較関数には、等しい(==)ときに true を返す関数を指定します。
	auto equal3 = std::equal(r1.begin(), r1.end(), r2.begin(),
		[](int a, int b) { std::cout << a << "," << b << " "; return a == b; });
	std::cout << std::boolalpha << equal3 << std::endl;
	// 1,1 2,2 3,3 4,4 5,5 true

	// 2つの範囲が等しくない位置を検索します。
	auto mismatch = std::mismatch(r1.begin(), r1.end(), r2.begin());
	output(r1, mismatch.first); // 位置:5 値:end
	output(r2, mismatch.second); // 位置:5 値:6

	// r1 が r2 より辞書的に小さいか比較します。
	auto lexicographical_compare = std::lexicographical_compare(r1.begin(), r1.end(), r2.begin(), r2.end());
	std::cout << std::boolalpha << lexicographical_compare << std::endl;
	// true

	// r1 と r2 を辞書的に三方比較します。
#if __cplusplus >= 202002L
	auto lexicographical_compare_three_way = std::lexicographical_compare_three_way(r1.begin(), r1.end(), r2.begin(), r2.end());
	std::cout << std::boolalpha
		<< "<:" << (lexicographical_compare_three_way < 0)
		<< " ==:" << (lexicographical_compare_three_way == 0)
		<< " >:" << (lexicographical_compare_three_way > 0)
		<< std::endl;
	// <:true ==:false >:false
#else
	std::cout << "not supported. std::lexicographical_compare_three_way C++20; #if __cplusplus >= 202002L: " << __cplusplus << std::endl;
#endif

	return 0;
}
C++20 range指定
#include <algorithm>
#include <iostream>
#include <vector>

int main(int argc, char* argv[]) {
	std::vector<int> r1 = { 1, 2, 3, 4, 5 };
	std::vector<int> r2 = { 1, 2, 3, 4, 5, 6 };

	// 2つの範囲が等しいか比較します。
	auto equal = std::ranges::equal(r1, r2);
	std::cout << std::boolalpha << equal << std::endl;
	// false

	// 比較関数には、等しい(==)ときに true を返す関数を指定します。
	auto equal3 = std::ranges::equal(r1, r2,
		[](int a, int b) { std::cout << a << "," << b << " "; return a == b; });
	std::cout << std::boolalpha << equal3 << std::endl;
	// false

	// 2つの範囲が等しくない位置を検索します。
	auto mismatch = std::ranges::mismatch(r1, r2);
	output(r1, mismatch.in1); // 位置:5 値:end
	output(r2, mismatch.in2); // 位置:5 値:6

	// r1 が r2 より辞書的に小さいか比較します。
	auto lexicographical_compare = std::ranges::lexicographical_compare(r1, r2);
	std::cout << std::boolalpha << lexicographical_compare << std::endl;
	// true

	return 0;
}

コメント

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