前回はArray.Copyを使って、配列の全要素を別の配列にコピーする方法を見ました。今回はその続きとして、コピーする範囲を指定する方法を見ていきます。「先頭から何個だけ」というコピーと、「何番目から何個」という開始位置まで指定するコピーの2つを順番に確認します。
ボタンの追加と準備
これまでと同じように、フォームに新しいボタンを1つ追加します。ボタンの表示文字は「範囲指定のコピー」としておきます。追加したボタンをダブルクリックして、クリックイベントのメソッドを作ります。
図1 フォームに「範囲指定のコピー」ボタンを追加する
メソッドができたら、前回のレクチャーで書いたhaiAとhaiBの2行をコピーして貼り付けます。haiAは10、20、30の3要素を持つコピー元、haiBはhaiAと同じ要素数を持つコピー先です。
リスト1 コピー元とコピー先の配列を用意する
private void button11_Click(object sender, EventArgs e)
{
//範囲指定のCopy
var haiA = new int[] { 10, 20, 30 };
var haiB = new int[haiA.Length];
}
図2 前回の配列haiA、haiBを貼り付けた状態
先頭から個数を指定してコピーする
まず前回の書き方を振り返ります。前回は次のように書きました。
リスト2 前回のコード(全件コピー)
Array.Copy(haiA, haiB, haiA.Length);
図3 前回書いたArray.Copyの呼び出し
Array.Copyの1つ目の引数がコピー元、2つ目がコピー先、そして3つ目が「何個コピーするか」です。前回は3つ目の引数にコピー元のLength、つまりhaiA.Lengthを指定したので、全件がコピー対象になりました。
ということは、この3つ目の引数を変えれば、コピーする個数を変えられます。たとえば2にすると、前から2個だけがコピーされます。
リスト3 先頭から2個だけコピーする
var haiA = new int[] { 10, 20, 30 };
var haiB = new int[haiA.Length];
Array.Copy(haiA, haiB, 2);
図4 3つ目の引数を2に変更する
ブレークポイントを置いて実行し、ウォッチウィンドウで2つの配列の中身を確認します。
図5 ウォッチウィンドウでhaiAとhaiBを確認する
haiAは10、20、30ですが、haiBは10と20だけが入っていて、3つ目は0のままです。コピーされなかった要素は、配列を生成したときの初期値がそのまま残ります。
このように「コピー元の0番目から何個」というコピーであれば、前回と同じ3引数の書き方のままで対応できます。
コピー先に必要な要素数
ちなみに、コピー先の配列は、コピーしてくる個数の分だけ要素があれば十分です。2個しかコピーしないのであれば、コピー先は要素数2で作っておけば問題ありません。
リスト4 要素数2の配列にコピーする
var haiC = new int[2]; Array.Copy(haiA, haiC, 2);
図6 要素数2の配列haiCを作る
実行してhaiCにマウスを当てると、10と20が入っていることが確認できます。
図7 haiCには10と20がコピーされている
では、この要素数2のhaiCに対して、3個コピーしようとするとどうなるでしょうか。3つ目の引数をhaiA.Lengthにして試してみます。
リスト5 コピー先の領域が足りないケース
var haiC = new int[2]; Array.Copy(haiA, haiC, 2); Array.Copy(haiA, haiC, haiA.Length); //3個コピーしようとする
haiCには2個分の場所しかないので、3個目を入れる場所がありません。実行すると例外になります。
図8 System.ArgumentExceptionが発生する
発生するのはSystem.ArgumentExceptionで、メッセージには「Destination array was not long enough」、つまりコピー先の配列の長さが足りないと書かれています。コピー先には、コピーしてくる個数の分の要素が必ず必要だということです。
確認ができたので、この行はコメントアウトし、注意点をコメントとして残しておきます。
リスト6 例外になる行をコメントアウトしておく
var haiC = new int[2]; Array.Copy(haiA, haiC, 2); //コピー先の領域が足りない場合は例外となる //Array.Copy(haiA, haiC, haiA.Length);
図9 コメントを付けてコメントアウトした状態
開始位置を指定してコピーする
ここまでは「0番目から何個」というコピーでした。次は「何番目から何個」というように、スタートの位置も変えたい場合です。
まずコピー先の配列を作ります。ここでは要素数を2にします。
リスト7 コピー先の配列haiDを作る
//指定範囲をコピー var haiD = new int[2];
Array.Copyと書くところまでは同じですが、引数が5つになります。haiAの次にコピー元の開始インデックス、haiDの次にコピー先の開始インデックスを書き、最後にコピーする個数を書きます。入力中に表示されるシグネチャを見ると、sourceIndexとdestinationIndexという引数が増えていることがわかります。
図10 5つの引数を取るArray.Copyのシグネチャ
リスト8 開始位置を指定してコピーする
//指定範囲をコピー var haiD = new int[2]; Array.Copy(haiA, 1, haiD, 0, 2);
図11 Array.Copy(haiA, 1, haiD, 0, 2)と入力した状態
5つの引数は、前から順に次の意味になります。
リスト9 5つの引数の意味
Array.Copy(
haiA, //コピー元の配列
1, //コピー元の開始インデックス
haiD, //コピー先の配列
0, //コピー先の開始インデックス
2); //コピーする個数
つまり「haiAは1番目からスタートしてください、haiDは0番目からコピーしてください、それを2個してください」という指定です。コピー元はインデックスの1番目から2つ、コピー先はインデックスの0番目から2つ、という意味になります。
実行してhaiDの中身を確認します。
図12 haiDには20と30が入っている
haiDには20、30と入っています。コピー元のhaiAも確認しておきます。
図13 コピー元のhaiAは10、20、30
haiAは10、20、30です。インデックスは0から始まるので、1番目は20です。そこから2個、つまり20と30を移してくるように指定したので、haiDには20、30の2個が入っているということです。
まとめ
範囲を指定してコピーする場合は、コピー元のインデックスとコピー先のインデックスを指定し、あとは何個コピーするかを指定します。最後に、今回の内容をコメントとして残した完成形のコードを載せておきます。
図14 コメントを追記した完成形のコード
リスト10 今回のコード全体
private void button11_Click(object sender, EventArgs e)
{
//範囲指定のCopy
var haiA = new int[] { 10, 20, 30 };
var haiB = new int[haiA.Length];
Array.Copy(haiA, haiB, 2);
var haiC = new int[2];
Array.Copy(haiA, haiC, 2);
//コピー先の領域が足りない場合は例外となる
//Array.Copy(haiA, haiC, haiA.Length);
//指定範囲をコピー
var haiD = new int[2];
//コピー元のインデックスとコピー先のインデックスを指定、
//何個コピーするかを指定
//haiAの1番目、haiDは0番目から2個コピーする
Array.Copy(haiA, 1, haiD, 0, 2);
}
先頭から何個だけコピーするなら3引数、開始位置も変えたいなら5引数、と使い分けます。いずれの場合も、コピー先にはコピーする個数分の領域が必要です。このような形で、範囲を指定したコピーを試してみてください。
■非公開コース「C#14新機能」プレゼント:
非公開コース「C#14新機能」(80分)をご覧になりたい方は
こちらからURLとパスワードを発行していますので、ご覧になってみてください。
非公開コース「C#14新機能」を観る
A01_はじめに
A02_プロジェクトの作成
B01_配列とは
B02_配列の生成とアクセス
B03_生成と同時に値を設定する
B04_型推論による生成
B05_メソッドの引数などにする場合の注意点
B06_Length
B07_IndexOfでの検索
B08_FindIndexでの検索
B09_Find
B10_Exists
B11_FindAllとFindLast
B12_誤ったコピー
B13_Array.Copy
B14_範囲指定のコピー
B15_Resize
C01_ArrayList
C02_List
C03_List 動的な要素の変更
C04_Listのコンストラクタ
C05_Listのコンストラクタ_Capacity
C06_ListTからArrayクラスのメソッドが呼ばれている
D01_コレクションインタフェースとは
D02_異なるコレクションクラスに互換性を持たせる
D03_インタフェースの階層構造
D04_クライアントができる操作を制限させる
D05_クライアントができる操作を制限させる_後半
D06_Enumerableの拡張メソッドに関して
D07_ReadOnly系のコレクションインタフェース
D08_AsReadOnly
D09_ToListでコピーする
D10_ListTはprivateで使う
■非公開コース「C#14新機能」プレゼント:
非公開コース「C#14新機能」(80分)をご覧になりたい方は
こちらからURLとパスワードを発行していますので、ご覧になってみてください。
非公開コース「C#14新機能」を観る













