C++で配列の中身を以下のように初期化したい場合があります。

#include <iostream>
#include <array>

using namespace std;

int main()
{
	array<int , 10> arr;

	//配列の値を「0,1,2,...,N」と初期化
	int i = 0;
	for(auto& val : arr)
	{
		val = i++;
	}

	for(const auto val : arr)
	{
		cout << val << endl;
	}

	return 0;
}

もちろん、この書き方でも問題ありませんが、便利な関数としてiota(※itoaじゃないです)というものが実装されました。

#include <iostream>
#include <array>
#include <numeric>

using namespace std;

int main()
{
	array<int , 10> arr;

	//配列の値を「0,1,2,...,N」と初期化
	iota(arr.begin(), arr.end(), 0);

	for(const auto val : arr)
	{
		cout << val << endl;
	}

	return 0;
}

引数はそれぞれ、
・第一引数 シーケンス先頭
・第二引数 シーケンス終端
・第三引数 初期化の最初の値
となっています。つまり、第三引数に渡した値を始めとして、そこから順番に「+1」していった値を配列に代入しています。
他の例として、以下のように文字のA~Zまでを順番に入れるということもできます。

#include <iostream>
#include <array>
#include <numeric>

using namespace std;

int main()
{
	array<char , 26> arr;

	//配列の値を「A,B,C,...,Z」と初期化
	iota(arr.begin(), arr.end(), 'A');

	for(const auto val : arr)
	{
		cout << val << endl;
	}

	return 0;
}

今回のように、「0,1,2,...,N」と値が入った配列はその値を長さNの配列の添字として利用することが出来ます。

次にshuffleについて説明します。さっきのiotaによって生成した「0,1,2,...,N」という値を配列の添字に使えると言いましたが、順番にではなく、ランダムな添字で配列にアクセスしたいうことがあります。そのような場合に使えるのがshuffle関数です。

#include <iostream>
#include <array>
#include <numeric>
#include <algorithm>
#include <random>

using namespace std;

int main()
{
	array<int , 10> arr;

	//配列の値を「0,1,2,...,N」と初期化
	iota(arr.begin(), arr.end(), 0);

	for(const auto val : arr)
	{
		cout << val << ' ';
	}
	cout << endl;

	//random_deviceによるランダムに並び替え
	shuffle(arr.begin(), arr.end(), random_device{});

	for(const auto val : arr)
	{
		cout << val << ' ';
	}
	cout << endl;

	return 0;
}

shuffle関数の引数は
・第一引数 シーケンス先頭
・第二引数 シーケンス終端
・第三引数 乱数生成の種類
となっています。第三引数は、C++11講座10回で説明した乱数生成の種類(mt19937等)を指定してあげればいいです。
※実は、前からrandom_shuffleという同様の機能の関数があったのですが、乱数の生成が標準のrandを採用していたため精度が悪い問題がありました。(ちなみに、rand、srand、random_shuffleなどはC++14で非推奨になったらしいです。)

shuffleは以下のようにすれば、構造体やクラスの場合でも並び替えできます。

#include <iostream>
#include <array>
#include <algorithm>
#include <random>

//自作の構造体、クラスに対しても使用可能
struct Obj
{
	int x, y;

	Obj()
	{
		static int i = 0;
		this->x = this->y = i++;
	}

	//代入演算子のオーバーロードが必要
	Obj& operator=(const Obj& obj)
	{
		this->x = obj.x;
		this->y = obj.y;
		return *this;
	}
};

using namespace std;

int main()
{
	array<Obj , 10> arr;

	for(const auto val : arr)
	{
		cout << val.x << ' ' << val.y << endl;
	}
	cout << endl;

	//random_deviceによるランダムに並び替え
	shuffle(arr.begin(), arr.end(), random_device{});

	for(const auto val : arr)
	{
		cout << val.x << ' ' << val.y << endl;
	}

	return 0;
}

何かの要素の配列の順番をランダムにして使用する場面は意外とあるので、そのような場合はこのshuffleを使うといいでしょう。

前⇒続・C++11講座0回
次⇒続・C++11講座2回


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-12-13 (土) 17:00:10