例えば、配列の中でインデックスが2番目の要素から5つの要素を抜き出すというように、指定した範囲の要素を抜き出す方法を紹介します。
ちなみにコレクションでは、GetRangeメソッドを使って簡単に行うことができます。
まず、新しい配列を作成して、Array.Copyメソッドでコピーするという単純な方法が考えられます。次の例では、インデックスが2番目の要素から5つの要素を抜き出しています。
'基になる配列 Dim ary1 As Integer() = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 'コピー先の配列を作成する Dim ary2 As Integer() = New Integer(4) {} '指定された範囲をコピーする Array.Copy(ary1, 2, ary2, 0, 5) 'ary2は{ 2, 3, 4, 5, 6 }となる
//基になる配列 int[] ary1 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; //コピー先の配列を作成する int[] ary2 = new int[5]; //指定された範囲をコピーする Array.Copy(ary1, 2, ary2, 0, 5); //ary2は{ 2, 3, 4, 5, 6 }となる
Array.Copyメソッドの代わりにBuffer.BlockCopyメソッドを使うと、処理速度が上がります。ただしBuffer.BlockCopyメソッドは.NET Framework 2.0以降でのみ使用でき、さらに、プリミティブ型の配列だけに使用できます。Buffer.BlockCopyメソッドについて詳しくは、「複数の配列をマージする」をご覧ください。
以下にBuffer.BlockCopyメソッドを使った例を示します。
'基になる配列 Dim ary1 As Integer() = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 'コピー先の配列を作成する Dim ary2 As Integer() = New Integer(4) {} '型のサイズを取得する(Int32の場合は 4) Dim typeSize As Integer = System.Runtime.InteropServices.Marshal.SizeOf( _ ary1.[GetType]().GetElementType()) '指定された範囲をコピーする Buffer.BlockCopy(ary1, 2 * typeSize, ary2, 0, ary2.Length * typeSize)
//基になる配列 int[] ary1 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; //コピー先の配列を作成する int[] ary2 = new int[5]; //型のサイズを取得する(Int32の場合は 4) int typeSize = System.Runtime.InteropServices.Marshal.SizeOf( ary1.GetType().GetElementType()); //指定された範囲をコピーする Buffer.BlockCopy(ary1, 2 * typeSize, ary2, 0, ary2.Length * typeSize);
.NET Framework 3.5以降でLINQが使えるのであれば、Enumerable.Skipメソッドで指定した要素までスキップして、Enumerable.Takeメソッドで指定した数の要素を取得することができます。
以下にSkipメソッドとTakeメソッドを使った例を示します。
'Imports System.Linq '基になる配列 Dim ary1 As Integer() = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 'Skipで2つの要素を飛ばして、Takeで5つの要素を取得する Dim ary2 As Integer() = ary1.Skip(2).Take(5).ToArray()
//using System.Linq; //基になる配列 int[] ary1 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; //Skipで2つの要素を飛ばして、Takeで5つの要素を取得する int[] ary2 = ary1.Skip(2).Take(5).ToArray();
SkipとTakeメソッドに似たメソッドに、SkipWhileとTakeWhileメソッドがあります。SkipWhileメソッドは、要素が指定した条件に一致しなくなるまでスキップします。TakeWhileメソッドは、指定した条件に一致している間の要素を返します。
以下の例では、値が2以上の要素までスキップし、値が7未満の要素を取得しています。
'Imports System.Linq 'がソースファイルの一番上に書かれているものとする '基になる配列 Dim ary1 As Integer() = New Integer() {0, 1, 2, 3, 4, 5, _ 6, 7, 8, 9} 'SkipWhileで2未満の要素をスキップし、TakeWhileで7未満の要素を取得する Dim ary2 As Integer() = ary1.SkipWhile(Function(i) i < 2). _ TakeWhile(Function(i) i < 7).ToArray() 'ary2は{ 2, 3, 4, 5, 6 }となる
//using System.Linq; //がソースファイルの一番上に書かれているものとする //基になる配列 int[] ary1 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; //SkipWhileで2未満の要素をスキップし、TakeWhileで7未満の要素を取得する int[] ary2 = ary1.SkipWhile(i => i < 2).TakeWhile(i => i < 7).ToArray(); //ary2は{ 2, 3, 4, 5, 6 }となる
コレクションではGetRangeメソッドを使って指定した範囲の要素を抜き出すことができますので、配列をコレクションに変換してGetRangeメソッドを使うという方法も考えられます。ただしこの方法にはこれといったメリットがありませんので、上記の方法の方が優れているでしょう。
'基になる配列 Dim ary1 As Integer() = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 'ary1からコレクションを作成する '.NET Framework 2.0以降ならば、List(Of Integer)を使った方が良い Dim al As New System.Collections.ArrayList(ary1) '2番目から5つの要素を取り出す Dim rangeList As System.Collections.ArrayList = al.GetRange(2, 5) '配列に変換する Dim ary2 As Integer() = _ DirectCast(rangeList.ToArray(GetType(Integer)), Integer()) 'ary2は{ 2, 3, 4, 5, 6 }となる
//基になる配列 int[] ary1 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; //ary1からコレクションを作成する //.NET Framework 2.0以降ならば、List<int>を使った方が良い System.Collections.ArrayList al = new System.Collections.ArrayList(ary1); //2番目から5つの要素を取り出す System.Collections.ArrayList rangeList = al.GetRange(2, 5); //配列に変換する int[] ary2 = (int[])rangeList.ToArray(typeof(int)); //ary2は{ 2, 3, 4, 5, 6 }となる
新しい配列を作るわけではないため、ここで紹介するのが適当ではないかもしれませんが、何かの参考になるかもしれませんので、ArraySegment構造体を紹介しておきます。ArraySegment構造体は、.NET Framework 2.0以降で使用できます。
ArraySegment構造体は、1次元配列のラッパーで、配列内の要素を範囲(開始位置と長さ)を指定して区切るものです。ArraySegment構造体は、配列と開始位置と長さを覚えている程度で、大した機能はありません。
以下にArraySegmentで配列を区切り、区切られた範囲の要素を表示する例を示します。
'基になる配列 Dim ary1 As Integer() = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} '配列を区切る Dim arySeg As New ArraySegment(Of Integer)(ary1, 2, 5) '区切られた範囲の要素を表示する For i As Integer = arySeg.Offset To arySeg.Offset + arySeg.Count - 1 Console.WriteLine("{0}:{1}", i, arySeg.Array(i)) Next '以下のように表示される '2:2 '3:3 '4:4 '5:5 '6:6
//基になる配列 int[] ary1 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; //配列を区切る ArraySegment<int> arySeg = new ArraySegment<int>(ary1, 2, 5); //区切られた範囲の要素を表示する for (int i = arySeg.Offset; i < arySeg.Offset + arySeg.Count; i++) { Console.WriteLine("{0}:{1}", i, arySeg.Array[i]); } //以下のように表示される //2:2 //3:3 //4:4 //5:5 //6:6