コレクション【C#】

C#文法:コレクション:B14_範囲指定のコピー

前回はArray.Copyを使って、配列の全要素を別の配列にコピーする方法を見ました。今回はその続きとして、コピーする範囲を指定する方法を見ていきます。「先頭から何個だけ」というコピーと、「何番目から何個」という開始位置まで指定するコピーの2つを順番に確認します。

ボタンの追加と準備

これまでと同じように、フォームに新しいボタンを1つ追加します。ボタンの表示文字は「範囲指定のコピー」としておきます。追加したボタンをダブルクリックして、クリックイベントのメソッドを作ります。

図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 前回の配列haiA、haiBを貼り付けた状態

先頭から個数を指定してコピーする

まず前回の書き方を振り返ります。前回は次のように書きました。

リスト2 前回のコード(全件コピー)

Array.Copy(haiA, haiB, haiA.Length);

図3 前回書いたArray.Copyの呼び出し

図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に変更する

図4 3つ目の引数を2に変更する

ブレークポイントを置いて実行し、ウォッチウィンドウで2つの配列の中身を確認します。

図5 ウォッチウィンドウでhaiAとhaiBを確認する

図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を作る

図6 要素数2の配列haiCを作る

実行してhaiCにマウスを当てると、10と20が入っていることが確認できます。

図7 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が発生する

図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 コメントを付けてコメントアウトした状態

図9 コメントを付けてコメントアウトした状態

開始位置を指定してコピーする

ここまでは「0番目から何個」というコピーでした。次は「何番目から何個」というように、スタートの位置も変えたい場合です。

まずコピー先の配列を作ります。ここでは要素数を2にします。

リスト7 コピー先の配列haiDを作る

//指定範囲をコピー
var haiD = new int[2];

Array.Copyと書くところまでは同じですが、引数が5つになります。haiAの次にコピー元の開始インデックス、haiDの次にコピー先の開始インデックスを書き、最後にコピーする個数を書きます。入力中に表示されるシグネチャを見ると、sourceIndexとdestinationIndexという引数が増えていることがわかります。

図10 5つの引数を取るArray.Copyのシグネチャ

図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)と入力した状態

図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が入っている

図12 haiDには20と30が入っている

haiDには20、30と入っています。コピー元のhaiAも確認しておきます。

図13 コピー元のhaiAは10、20、30

図13 コピー元のhaiAは10、20、30

haiAは10、20、30です。インデックスは0から始まるので、1番目は20です。そこから2個、つまり20と30を移してくるように指定したので、haiDには20、30の2個が入っているということです。

まとめ

範囲を指定してコピーする場合は、コピー元のインデックスとコピー先のインデックスを指定し、あとは何個コピーするかを指定します。最後に、今回の内容をコメントとして残した完成形のコードを載せておきます。

図14 コメントを追記した完成形のコード

図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#文法:コレクション

■非公開コース「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新機能」を観る