配列の操作
Arrayクラス
配列は複数の同じデータ型をまとめて扱う機能です。
単純に複数の変数がひとつにまとめられるだけでなく、様々な便利な機能が提供されています。
ここでは配列操作でよく使用されるメソッド(関数)を解説します。
配列の操作のためのメソッドはArrayというクラスに存在します。
クラスと言うのは、ある機能を実現するためデータ群(変数や関数など)をひとつにまとめたものです。
なお、ごく基本的な事柄は 配列、多次元配列を参照してください。
- 配列の基本
- Array.Clear(要素のクリア)
- Array.Resize(要素数の変更)
- CopyTo(配列のコピー)
- Array.Copy(配列のコピー)
- Array.Clone(配列の複製)
- Array.Sort(要素の並べ替え)
- Array.Reverse(要素の前後反転)
- Contains(要素の存在判定)
- Array.IndexOf(要素の検索)
- Array.LastIndexOf(要素の後方検索)
- Array.BinarySearch(要素の二分検索)
- Array.Find(条件に合致する要素の取得)
配列の基本
配列のページでも説明している基本的な事柄を簡単におさらいしておきます。
//配列の宣言(要素数3)
int[] nums1 = new int[3];
//宣言と同時に初期化
int[] nums2 = new int[] { 1, 2, 3 };
//宣言と同時に初期化(省略形)
int[] nums3 = { 1, 2, 3 };
//各要素へのアクセス
int num = nums2[0]; //1
//要素数の取得
int length = nums2.Length; //3
配列のメソッド
Array.Clear(要素のクリア)
配列の要素をすべて既定値に設定するにはArray.Clearメソッドを使用します。
int[] nums = new int[] { 1, 2, 3, 4, 5 };
//配列をすべてクリア
//(先頭要素から配列の要素数分をクリア)
Array.Clear(nums, 0, nums.Length);
foreach (var n in nums)
Console.Write("{0}, ", n);
Console.WriteLine();
nums = new int[] { 1, 2, 3, 4, 5 };
//1番目の要素から2つ分をクリア
Array.Clear(nums, 1, 2);
foreach (var n in nums)
Console.Write("{0}, ", n);
0, 0, 0, 0, 0, 1, 0, 0, 4, 5,
Array.Clearは第一引数にクリアしたい配列を指定します。
第二引数はクリアを開始したい要素番号を指定します。
第三引数はクリアしたい要素数を指定します。
つまり要素をすべてクリアしたい場合は、第二引数に「0」、第三引数にその配列の要素数を指定します。
(5行目)
多次元配列の場合
多次元配列に対してArray.Clearメソッドを適用することもできます。
クリアする範囲は多次元配列を一次元配列とみなして指定します。
int[,] nums = new int[,] {
{ 0, 1, 2 },
{ 3, 4, 5 },
{ 6, 7, 8 },
};
//すべてクリア
Array.Clear(nums, 0, nums.Length);
nums = new int[,] {
{ 0, 1, 2 },
{ 3, 4, 5 },
{ 6, 7, 8 },
};
//2番目から5つ分をクリア
Array.Clear(nums, 2, 5);
foreach (var n in nums)
Console.Write("{0}, ", n);
0, 1, 0, 0, 0, 0, 0, 7, 8,
ジャグ配列の場合
ジャグ配列は「配列の配列」なので、そのままArray.Clearメソッドを適用すると一次元目(先頭要素)のみがクリアされます。
(配列は参照型なのでnullがセットされます)
二次元目の配列はクリアされません。
int[][] nums = new int[][] {
new int[] { 0, 1, 2 },
new int[] { 3, 4 },
new int[] { 5, 6, 7, 8 },
};
//一次元目をすべてクリア
Array.Clear(nums, 0, nums.Length);
上記のコードは二次元目の各配列は残ったままになり、アクセスする手段がなくなります。
ジャグ配列の要素をすべて削除する場合は後ろの次元の配列から順にクリアしていく必要があります。
int[][] nums = new int[][] {
new int[] { 0, 1, 2 },
new int[] { 3, 4 },
new int[] { 5, 6, 7, 8 },
};
//すべての二次元目の要素をクリア
for(int i = 0; i < nums.Length; i++)
{
Array.Clear(nums[i], 0, nums[i].Length);
}
//すべての一次元目の要素をクリア
Array.Clear(nums, 0, nums.Length);
アクセス手段がなくなった変数は自動的に消去されるので、単に一次元目のみをクリアしたとしても大きな問題にはなりません。
Array.Resize(要素数の変更)
配列の要素数を変更するにはArray.Resizeメソッドを使用します。
int[] nums = new int[] { 1, 2, 3 };
//要素数を5に変更
Array.Resize(ref nums, 5);
foreach (var n in nums)
Console.Write("{0}, ", n);
Console.WriteLine();
//要素数を2に変更
Array.Resize(ref nums, 2);
foreach (var n in nums)
Console.Write("{0}, ", n);
1, 2, 3, 0, 0, 1, 2,
Array.Resizeの第一引数には要素数を変更したい配列を指定します。
この時、refキーワードを指定する必要があります。
(refキーワードについては引数の参照渡しを参照)
第二引数には変更後の要素数を指定します。
変更前よりも要素数を増やした場合、新しい要素には既定値が設定されます。
変更前よりも要素数を減らした場合は切り捨てられます。
多次元配列の場合
Array.Resizeメソッドを多次元配列に適用することはできません。
(コンパイルエラー)
ジャグ配列の場合
ジャグ配列にArray.Resizeメソッドを適用すると一次元目の要素数を変更できます。
配列は参照型なので、要素数を増した場合は新しく作られた要素には既定値であるnullが入ります。
二次元目の要素数を変更する場合は格納されているそれぞれの配列にアクセスした上でArray.Resizeメソッドを適用します。
CopyTo(配列のコピー)
コピー元配列のすべてを、コピー先配列のコピー開始番号を指定してコピーするにはCopyToメソッドを使用します。
int[] nums1 = new int[] { 1, 2, 3 };
int[] nums2 = new int[] { 4, 5, 6, 7 };
//nums1のすべてをnums2の1番目の要素からコピー
nums1.CopyTo(nums2, 1);
foreach(var n in nums2)
Console.Write("{0}, ", n);
4, 1, 2, 3,
CopyToメソッドは、まずコピー元となる配列を記述し、「.CopyTo」を記述します。
CopyToメソッドの第一引数に、コピー先となる配列名を指定します。
第二引数には、コピー先の配列の何番目からコピーを開始するか(index)を指定します。
「index + コピー元の配列の要素数」よりもコピー先の配列の要素数が少ない場合はエラー(例外)になります。
また、indexにマイナス値を指定してもエラーになります。
CopyToメソッドはコピー元の配列がコピー先の配列にすべてコピーされます。
コピー先配列の何番目からコピーをするかを指定することはできますが、使い勝手がイマイチなので次に説明するArray.Copyの使用を推奨します。
多次元配列の場合
Copyメソッドは多次元配列には使用できません。
多次元配列のコピーは後述するArray.Copyメソッドを使用します。
ジャグ配列の場合
ジャグ配列にCopyToメソッドを適用すると一次元目の要素(配列)のコピーができます。
ただしコピー先の配列もジャグ配列である必要があります。
格納されている配列の要素のコピーを行う場合はその配列にアクセスした上でCopyToメソッドを適用します。
int[][] nums1 = new int[][] {
new int[] { 0, 1, 2 },
new int[] { 3, 4 },
new int[] { 5, 6, 7, 8 },
};
int[] nums2 = new int[4];
//nums1の2番目の要素を
//nums2にコピー
nums1[2].CopyTo(nums2, 0);
foreach(var n in nums2)
Console.Write("{0}, ", n);
4, 6, 7, 8,
Array.Copy(配列のコピー)
コピー元配列の先頭から任意の要素数を、コピー先配列の先頭へコピーするにはArray.Copyメソッドを使用します。
int[] nums1 = new int[] { 1, 2, 3 };
int[] nums2 = new int[] { 4, 5, 6, 7 };
//nums1の先頭から、nums2の先頭へ、要素数2つ分コピー
Array.Copy(nums1, nums2, 2);
foreach (var n in nums2)
Console.Write("{0}, ", n);
1, 2, 6, 7,
第一引数にコピー元、第二引数にコピー先となる配列を指定します。
第三引数はコピーする要素数を指定します。
コピーは先頭から行われます。
要素をすべてをコピーする場合は第三引数に配列の要素数を指定すれば良いですが、指定した値がコピー元もしくはコピー先の配列の要素数よりも大きい場合はエラー(例外)が発生します。
つまり、要素数の少ないほうに合わせる必要があります。
Array.Copyは、コピー元配列のコピー開始番号と長さ、コピー先配列のコピー開始番号を指定してコピーすることもできます。
int[] nums1 = new int[] { 1, 2, 3 };
int[] nums2 = new int[] { 4, 5, 6, 7 };
//nums1の1番目の要素から、nums2の1番目の要素へ、要素数2つ分コピー
Array.Copy(nums1, 1, nums2, 1, 2);
foreach (var n in nums2)
Console.Write("{0}, ", n);
4, 2, 3, 7,
こちらは引数が多いですが、その分柔軟なコピーが可能です。
多次元配列の場合
Array.Copyは多次元配列のコピーも可能です。
ただしコピー元とコピー先は同じ次元の配列である必要があります。
(コピー元が二次元配列ならコピー先も二次元配列)
コピー先配列の要素数さえ足りていればそれぞれの次元の要素数は自由です。
コピーする範囲は多次元配列を一次元配列とみなして指定します。
int[,] nums = new int[3, 4] {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};
int[,] nums2 = new int[2, 6];
//コピー先配が二次元配列で
//要素数が10以上あれば
//コピー可能
Array.Copy(nums, nums2, 10);
foreach (var n in nums2)
Console.Write("{0}, ", n);
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0,
ジャグ配列の場合
ジャグ配列にArray.Copyメソッドを適用すると一次元目の要素(配列)のコピーができます。
ただしコピー先の配列もジャグ配列である必要があります。
格納されている配列の要素のコピーを行う場合はその配列にアクセスした上でArray.Copyメソッドを適用します。
int[][] nums1 = new int[][] {
new int[] { 0, 1, 2 },
new int[] { 3, 4 },
new int[] { 5, 6, 7, 8 },
};
int[] nums2 = new int[4];
//nums1の0番目の配列の先頭要素から3つ分を
//nums2にコピー
Array.Copy(nums1[0], nums2, 3);
foreach(var n in nums2)
Console.Write("{0}, ", n);
0, 1, 2, 0,
Array.Clone(配列の複製)
配列を複製するにはArray.Cloneメソッドを使用します。
int[] nums1 = new int[] { 1, 2, 3 };
int[] nums2;
//nums1の複製を作り、nums2に代入
//キャストが必要
nums2 = nums1.Clone() as int[];
//こちらのキャストでも良い
//nums2 = (int[])nums1.Clone();
foreach (var n in nums2)
Console.Write("{0}, ", n);
1, 2, 3,
戻り値はobject型のため、キャストして受け取る必要があります。
多次元配列、ジャグ配列の場合
Array.Cloneメソッドは多次元配列やジャグ配列にも適用できます。
使い方は一次元配列と同じで、複製元と同じ型にキャストして受け取ります。
コピーメソッドの注意点
配列のコピーメソッド(CopyToやArray.Cloneなど)が行うのはシャローコピーです。
値型の配列の場合は問題ありませんが、参照型を要素とする配列の場合はアドレスのコピーになることに注意してください。
int[][] nums1 = new int[][] {
new int[] { 1, 2, 3 },
new int[] { 4, 5, 6 }
};
int[][] nums2 = nums1.Clone() as int[][];
//複製後に複製元の値を書き換え
nums1[0][0] = 9;
foreach (var x in nums1)
foreach (var y in x)
Console.Write("{0}, ", y);
Console.WriteLine();
foreach (var x in nums1)
foreach (var y in x)
Console.Write("{0}, ", y);
9, 2, 3, 4, 5, 6, 9, 2, 3, 4, 5, 6,
ジャグ配列(配列の配列)の各先頭要素には配列型が入っています。
配列は参照型ですので、Array.Cloneメソッドを使用するとシャローコピーになります。
上記サンプルコードでは、配列の複製後に複製元にした配列の要素を書き換えています。
シャローコピーなので、複製先の配列の要素も書き変わっていることがわかります。
Array.Sort(要素の並べ替え)
配列の要素を並べ替えるにはArray.Sortメソッドを使用します。
int[] nums = new int[] { 12, 16, 0, 7, 5 };
//並べ替え
Array.Sort(nums);
foreach (var n in nums)
Console.Write("{0}, ", n);
0, 5, 7, 12, 16,
Array.Sortメソッドは要素を昇順に並べ替えます。
降順に並べ替える場合はArray.Reverseメソッドと組み合わせて使用します。
以下のように、並べ替えの開始番号と要素数を指定することで、特定の範囲だけを並び替えすることもできます。
int[] nums = new int[] { 12, 16, 0, 7, 5 };
//1番目の要素から3つ分を並べ替え
Array.Sort(nums, 1, 3);
foreach (var n in nums)
Console.Write("{0}, ", n);
12, 0, 7, 16, 5,
メソッドを使用した並べ替え
Array.Sortメソッドは並べ替え用のメソッドを使用することで、順序を任意に変更できます。
例えばstring型の並べ替えは通常はABC順(あいうえお順)ですが、以下のコードは「文字数が少ない順」「同じ文字数の場合はABC順」というルールで並べ替えをしています。
//Sortメソッド用の比較メソッド
//負数を返すとxが手前になる
//正数を返すとyが手前になる
//ゼロを返すと両者は同じ
static int CompareString(string x, string y)
{
//nullチェック
if (x == null && y == null)
return 0;
if (x == null)
return -1;
if (y == null)
return 1;
if (x.Length < y.Length)
return -1;
if (x.Length > y.Length)
return 1;
//文字数が同じ場合は通常通り
return string.Compare(x, y);
}
static void Main(string[] args)
{
var strs = new string[]
{ "Tom", "James", "Michael", "Chris", "Boby" };
Array.Sort(strs);
foreach (var s in strs)
Console.Write("{0}, ", s);
Console.WriteLine();
//比較メソッドを使用して並べ替え
Array.Sort(strs, CompareString);
foreach (var s in strs)
Console.Write("{0}, ", s);
Console.ReadLine();
}
Boby, Chris, James, Michael, Tom, Tom, Boby, Chris, James, Michael,
多次元配列の場合
Array.Sortメソッドは多次元配列の並べ替えはできません。
ジャグ配列の場合
Array.Sortメソッドでジャグ配列を並べ替えるには、並べ替えのためのメソッドを自分で定義する必要があります。
ジャグ配列は「配列の配列」であるため、配列同士を比較するのですが、これは数値や文字列のように何を基準として比較するかが明確でありません。
そこで自分で比較のためのルールを作るのです。
以下のコードは
- 二つの配列を先頭要素から比較していく
- 異なる値が検出されたとき、値が小さいほうを手前とする
- 2で順序が決定されなかった場合、両配列の要素数を比較し、要素数が少ないほうを手前とする
- 要素数も同じ場合は両配列は全く同じ(並べ替えの必要がない)
というルールで比較した例です。
具体的な処理はコード中のコメントを参照してください。
//Array.Sort用の配列の比較メソッド
//負数を返すとxが手前になる
//正数を返すとyが手前になる
//ゼロを返すと両者は同じ
static int CompareArray(int[] x, int[] y)
{
//要素数の少ないほうを取得
int min = x.Length < y.Length ? x.Length : y.Length;
//ちなみにこんなメソッドもある
//int min = Math.Min(x.Length, y.Length);
//同じ要素番号同士を比較
//異なる値が出現した時、小さいほうを手前とする
for (int i = 0; i < min; i++)
{
if (x[i] < y[i])
return -1;
else if (x[i] > y[i])
return 1;
}
//↑の処理で値がすべて同じだった場合は
//要素数の少ないほうを手前にする
if (x.Length < y.Length)
return -1;
else if (x.Length > y.Length)
return 1;
else //要素数まで同じ場合は両者は完全に同じ
return 0;
}
static void Main(string[] args)
{
int[][] nums = new int[][] {
new int[] { 0, 1 },
new int[] { 0, 2 },
new int[] { 1, 2 },
new int[] { 0, 1, 2 },
new int[] { 0, 2, 3 },
new int[] { 1, 2, 3 },
new int[] { 0, 1, 2, 3 }
};
//専用メソッドを使用して並べ替え
Array.Sort(nums, CompareArray);
foreach (var arr in nums)
{
foreach (var n in arr)
Console.Write("{0}, ", n);
Console.WriteLine();
}
Console.ReadLine();
}
0, 1, 0, 1, 2, 0, 1, 2, 3, 0, 2, 0, 2, 3, 1, 2, 1, 2, 3,
第一引数は並べ替えたいメソッドを指定します。
第二引数に、自作した並べ替え用メソッドを指定します。
第二引数のメソッドの指定には通常のメソッド呼び出しのように引数は記述せず、丸括弧(関数呼び出し演算子)も記述しません。
これはArray.Sortメソッドに比較用メソッドとして何を使用するかを指定しているだけで、実際のメソッド呼び出しはArray.Sortメソッドが自動的に行います。
メソッドの仮引数もArray.Sortメソッドが自動的にセットします。
Array.Reverse(要素の前後反転)
配列の要素の並びを反転させるにはArray.Reverseメソッドを使用します。
int[] nums = new int[] { 12, 16, 0, 7, 5 };
//前後反転
Array.Reverse(nums);
foreach (var n in nums)
Console.Write("{0}, ", n);
5, 7, 0, 16, 12,
Array.Sortメソッドと同様に、範囲を指定して一部だけを反転することもできます。
int[] nums = new int[] { 12, 16, 0, 7, 5 };
//1番目の要素から3つ分を反転
Array.Reverse(nums, 1, 3);
foreach (var n in nums)
Console.Write("{0}, ", n);
12, 7, 0, 16, 5,
要素を降順で並べ替え
要素を降順に並べ替えるにはArray.Sortメソッドを適用してからArray.Reverseメソッドを適用します。
int[] nums = new int[] { 12, 16, 0, 7, 5 };
//昇順並べ替え
Array.Sort(nums);
//前後反転
Array.Reverse(nums);
foreach (var n in nums)
Console.Write("{0}, ", n);
16, 12, 7, 5, 0,
多次元配列の場合
Array.Reverseメソッドは多次元配列の反転はできません。
ジャグ配列の場合
ジャグ配列は先頭要素(一次元目)の要素が反転されます。
格納されている配列の要素の反転を行う場合はその配列にアクセスした上でArray.Reverseメソッドを適用します。
Contains(要素の存在判定)
配列の要素に特定の値が存在するか否かを判定するにはContainsメソッドを使用します。
これはインスタンスメソッドです。
厳密にはContainsメソッドは配列に固有のメソッドではありませんが、便利なので紹介します。
Containsメソッドの使用にはコードの先頭に「using System.Linq;」が必要です。
using System;
using System.Linq; //←これが必要
//その他のusing~の行は変更しなくて良い
namespace ConsoleApplication1
{
//以降省略
int[] nums = new int[] { 12, 16, 0, 7, 5 };
int num1 = 12;
int num2 = 13;
Console.Write("配列nums内に「{0}」は存在しま", num1);
if (nums.Contains(num1))
Console.WriteLine("す。");
else
Console.WriteLine("せん。");
Console.Write("配列nums内に「{0}」は存在しま", num2);
if (nums.Contains(num2))
Console.WriteLine("す。");
else
Console.WriteLine("せん。");
配列nums内に「12」は存在します。 配列nums内に「13」は存在しません。
Containsメソッドは引数に指定した値が配列内に一つでも含まれていれば真(true)を返します。
一つも見つからなければ偽(false)を返します。
要素が配列内のどの位置に存在するかを知りたい場合は後述のArray.IndexOf、Array.LastIndexOfなどを使用します。
多次元配列、ジャグ配列の場合
Containsメソッドは多次元配列やジャグ配列には使用できません。
Array.IndexOf(要素の検索)
配列から要素を検索するにはArray.IndexOfメソッドを使用します。
int[] nums = new int[] { 5, 12, 16 };
//「12」を検索
int index1 = Array.IndexOf(nums, 12);
//「13」を検索
int index2 = Array.IndexOf(nums, 13);
Console.WriteLine(index1);
Console.WriteLine(index2);
1 -1
先頭の要素は「0番目」であることに注意してください。
第一引数に検索対象の配列を指定します。
第二引数は検索したい値を指定します。
要素が見つかった場合はその要素番号を返します。
見つからなかった場合は「-1」を返します。
Array.IndexOfメソッドは先頭から検索し、最初に見つかった要素の要素番号を返します。
以下のように柔軟な検索も可能です。
int[] nums = new int[] { 5, 12, 16, 3, 7, 16 };
//すべての要素から「16」を検索
int index1 = Array.IndexOf(nums, 16);
//3番目の要素以降から「16」を検索
//検索対象: 3, 7, 16
int index2 = Array.IndexOf(nums, 16, 3);
//3番目の要素から2つ分まで「16」を検索
//検索対象: 3, 7
int index3 = Array.IndexOf(nums, 16, 3, 2);
Console.WriteLine(index1);
Console.WriteLine(index2);
Console.WriteLine(index3);
2 5 -1
例えば該当する要素をすべて表示するには以下のようにします。
int[] nums = new int[] { 0, 12, 16, 0, 7, 0, 3 };
int index = -1;
//「0」が出現する位置をすべて表示
while(true)
{
//前回見つかった要素以降を検索対象にするために1を加算する
index = Array.IndexOf(nums, 0, index + 1);
if (index >= 0)
{
Console.WriteLine(index);
continue;
}
break;
}
0 3 5
単純に「要素が存在するか否か」だけで良い場合はContainsメソッドを使用したほうが良いです。
多次元配列、ジャグ配列の場合
Array.IndexOfメソッドは多次元配列やジャグ配列の検索はできません。
Array.LastIndexOf(要素の後方検索)
Array.IndexOfメソッドは配列の先頭から要素を検索しますが、後方から検索したい場合はArray.LastIndexOfメソッドを使用します
int[] nums = new int[] { 0, 12, 16, 0, 7, 0, 3 };
//前方検索
int index = Array.IndexOf(nums, 0);
//後方検索
int lastIndex = Array.LastIndexOf(nums, 0);
Console.WriteLine(index);
Console.WriteLine(lastIndex);
0 5
検索が後方から行われる以外はArray.IndexOfメソッドと同じです。
戻り値は後ろから数えた番号ではなく要素番号なので注意してください。
多次元配列、ジャグ配列の場合
Array.LstIndexOfメソッドは多次元配列やジャグ配列の検索はできません。
Array.BinarySearch(要素の二分検索)
要素の検索にはArray.BinarySearchメソッドを使用する方法もあります。
Array.IndexOfメソッドは要素を先頭から順番に検索していきますが、Array.BinarySearchメソッドは二分検索という方法で検索を行います。
この検索方法はArray.IndexOfメソッドよりも高速な検索が可能ですが、要素が昇順で並べ替えられていなければなりません。
よって、Array.BinarySearchメソッドを使用する前にArray.Sortメソッドを適用しておく必要があります。
(昇順で並べ替えられていることが確定している場合は必要ありません)
int[] nums = new int[] { 12, 16, 0, 7, 5 };
//昇順で並べ替え
Array.Sort(nums);
//「12」を検索
int index = Array.BinarySearch(nums, 12);
foreach (var n in nums)
Console.Write("{0}, ", n);
Console.WriteLine("\n「12」は{0}番目", index);
0, 5, 7, 12, 16, 「12」は3番目
Array.BinarySearchは検索する要素がIComparableインターフェイスが実装されている必要があります。
詳しい説明は省きますが、自作クラスを検索する場合には注意が必要です。
int型などの組み込み型のデータ型の場合は問題ありません。
多次元配列、ジャグ配列の場合
Array.BinarySearchメソッドは多次元配列やジャグ配列の検索はできません。
Array.Find(条件に合致する要素の取得)
ある条件に合致する要素を取得するにはArray.Findメソッドを使用します。
これはデータ検索用のメソッドと、Predicate(術語)という特殊なデータ型を使用して要素を検索します。
//引数が10以上なら真を返す関数
static bool IsGTE10(int n)
{
return n >= 10;
}
static void Main(string[] args)
{
int[] nums1 = new int[] { 3, 16, 0, 7, 5 };
int[] nums2 = new int[] { 1, 2, 3 };
Predicate<int> isGTE10 = IsGTE10;
int index1 = Array.Find(nums1, isGTE10);
int index2 = Array.Find(nums2, isGTE10);
Console.WriteLine(index1);
Console.WriteLine(index2);
Console.ReadLine();
}
16 0
まず、条件判定用のメソッドを作ります。
自作メソッドIsGTE10は、引数に指定した数値が10以上ならば真を返すメソッドです。
(Is Greater Than or Equal to 10)
引数の型は使用したい配列のデータ型に合わせます。
次に、「Predicate<int>」というデータ型の変数を用意します。
「<>」の中には、先ほど自作したメソッドの引数のデータ型を指定します。
変数名は自由です。
Predicate<int>型の変数には先ほど定義した自作メソッドIsGTE10を代入します。
ここでメソッドを呼び出すわけではないので、関数呼び出し演算子(丸括弧)は記述しません。
このメソッドの実際の呼び出しはArray.Findメソッドが行います。
最後に、Array.Findメソッドを実行します。
第一引数は検索対象の配列を指定します。
第二引数には「Predicate<int>」型の変数を指定します。
戻り値は最初に条件に合致する要素です。
合致する要素がない場合は既定値を返します。
(int型の場合は「0」)
Array.IndexOfメソッドとは違い要素番号ではないことに注意してください。
ラムダ式による記述
Array.Findメソッドは「メソッドを用意して、それを変数に代入してから使用する」というやや面倒くさい手順が必要です。
これはラムダ式という記法を用いると少し簡潔に書くことができます。
static void Main(string[] args)
{
int[] nums = new int[] { 3, 16, 0, 7, 5 };
int index = Array.Find(nums, (x) => x >= 10);
Console.WriteLine(index);
Console.ReadLine();
}
16
Array.Findメソッドの仲間
術語を用いて条件判定を行うメソッドは他にも存在します。
使い方は同じなので、以下にまとめて示します。
詳細はコード中のコメントを参照してください。
static bool IsGTE10(int n)
{
return n >= 10;
}
static void Main(string[] args)
{
int[] nums = new int[] { 3, 16, 0, 12, 15, 8 };
Predicate<int> isGTE10 = IsGTE10;
//最初に見つかった要素を返す
int find =
Array.Find(nums, isGTE10);
//最後に見つかった要素を返す
int findLast =
Array.FindLast(nums, isGTE10);
//最初に見つかった要素の要素番号を返す
int findIndex =
Array.FindIndex(nums, isGTE10);
//最後に見つかった要素の要素番号を返す
int findLastIndex =
Array.FindLastIndex(nums, isGTE10);
//条件に合致するすべての要素を配列で返す
int[] findAll =
Array.FindAll(nums, isGTE10);
//条件に合致する要素が存在するかを真偽値で返す
bool exists =
Array.Exists(nums, isGTE10);
//すべての要素が条件に合致するかを真偽値で返す
bool trueForAll =
Array.TrueForAll(nums, isGTE10);
Console.Write("検索対象の配列: ");
foreach (var n in nums)
Console.Write("{0}, ", n);
Console.WriteLine("\n検索条件: n >= 10\n");
Console.WriteLine("Find: {0}", find);
Console.WriteLine("FindLast: {0}", findLast);
Console.WriteLine("FindIndex: {0}", findIndex);
Console.WriteLine("FindLastIndex: {0}", findLastIndex);
Console.Write("FindAll: ");
foreach (var n in findAll)
Console.Write("{0}, ", n);
Console.WriteLine();
Console.WriteLine("Exists: {0}", exists);
Console.WriteLine("TrueForAll: {0}", trueForAll);
Console.ReadLine();
}
検索対象の配列: 3, 16, 0, 2, 15, 8, 検索条件: x >= 10 Find: 16 FindLast: 15 FindIndex: 1 FindLastIndex: 4 FindAll: 16, 12, 15, Exists: True TrueForAll: False
Array.FindIndexメソッドとArray.FindLastIndexメソッドは、要素が見つからなかった場合は「-1」を返します。
またこれらのメソッドにはオーバーロードが存在します。
static bool IsGTE10(int n)
{
return n >= 10;
}
static void Main(string[] args)
{
int[] nums = new int[] { 0, 1, 12, 3, 4, 15 };
Predicate<int> isGTE10 = IsGTE10;
//3番目の要素から検索開始
int findIndex1 = Array.FindIndex(nums, 3, isGTE10);
//3番目の要素から2つ分を検索
int findIndex2 = Array.FindIndex(nums, 3, 2, isGTE10);
//4番目の要素から検索開始
int findLastIndex1 = Array.FindLastIndex(nums, 4, isGTE10);
//4番目の要素から2つ分を検索
int findLastIndex2 = Array.FindLastIndex(nums, 4, 2, isGTE10);
Console.WriteLine(findIndex1);
Console.WriteLine(findIndex2);
Console.WriteLine(findLastIndex1);
Console.WriteLine(findLastIndex2);
Console.ReadLine();
}
5 -1 2 -1
Array.FindLastIndexメソッドは後方から検索する以外はArray.FindIndexメソッドと同じです。
検索開始番号の指定や戻り値などはすべて配列の要素番号です。
後方から検索すると言ってもこれらも前後逆になるわけではないので注意してください。