ここでは、複数の配列やコレクションをくっつけて1つにする(マージする)方法を紹介します。例えば、{ 1, 2, 3 }と{ 4, 5, 6 }という配列をマージして、{ 1, 2, 3, 4, 5, 6 }という配列を作るということです。
コレクションの場合は、AddRangeメソッドで簡単に行うことができます。
AddRangeメソッドはマージするコレクションを末尾に追加しますが、InsertRangeメソッドを使えば、挿入する位置を指定することもできます。
以下に示す例では、AddRangeメソッドを使ってArrayListをマージしています。
'マージする2つのコレクション Dim list1 As New System.Collections.ArrayList(New Integer() {1, 2, 3}) Dim list2 As New System.Collections.ArrayList(New Integer() {4, 5, 6}) 'list1の末尾にlist2を追加する list1.AddRange(list2) 'list1は{ 1, 2, 3, 4, 5, 6 }となる
//マージする2つのコレクション System.Collections.ArrayList list1 = new System.Collections.ArrayList(new int[] { 1, 2, 3 }); System.Collections.ArrayList list2 = new System.Collections.ArrayList(new int[] { 4, 5, 6 }); //list1の末尾にlist2を追加する list1.AddRange(list2); //list1は{ 1, 2, 3, 4, 5, 6 }となる
次のように配列をコレクションに変換すれば、この方法で配列もマージできます。この例ではListを使用していますが、ArrayListでも同様にできます。
'マージする2つの配列 Dim ary1 As Integer() = New Integer() {1, 2, 3} Dim ary2 As Integer() = New Integer() {4, 5, 6} 'コレクションを作成する Dim mergedList As New System.Collections.Generic.List(Of Integer)( _ ary1.Length + ary2.Length) '配列をコレクションに追加する mergedList.AddRange(ary1) mergedList.AddRange(ary2) '配列に変換する Dim mergedArray As Integer() = mergedList.ToArray() 'mergedArrayは{ 1, 2, 3, 4, 5, 6 }となる
//マージする2つの配列 int[] ary1 = new int[] { 1, 2, 3 }; int[] ary2 = new int[] { 4, 5, 6 }; //コレクションを作成する System.Collections.Generic.List<int> mergedList = new System.Collections.Generic.List<int>( ary1.Length + ary2.Length); //配列をコレクションに追加する mergedList.AddRange(ary1); mergedList.AddRange(ary2); //配列に変換する int[] mergedArray = mergedList.ToArray(); //mergedArrayは{ 1, 2, 3, 4, 5, 6 }となる
ただし配列の場合は、以下に紹介する方法の方が優れています。
配列の場合は、マージ先として新しい配列を作成しておいて、そこにマージする配列のデータをArray.Copyメソッドでコピーするという方法が考えられます。以下にその例を示します。
'マージする2つの配列 Dim ary1 As Integer() = New Integer() {1, 2, 3} Dim ary2 As Integer() = New Integer() {4, 5, 6} '新しい配列を作る Dim mergedArray As Integer() = New Integer(ary1.Length + ary2.Length - 1) {} 'マージする配列のデータをコピーする Array.Copy(ary1, mergedArray, ary1.Length) Array.Copy(ary2, 0, mergedArray, ary1.Length, ary2.Length) 'mergedArrayは{ 1, 2, 3, 4, 5, 6 }となる
//マージする2つの配列 int[] ary1 = new int[] { 1, 2, 3 }; int[] ary2 = new int[] { 4, 5, 6 }; //新しい配列を作る int[] mergedArray = new int[ary1.Length + ary2.Length]; //マージする配列のデータをコピーする Array.Copy(ary1, mergedArray, ary1.Length); Array.Copy(ary2, 0, mergedArray, ary1.Length, ary2.Length); //mergedArrayは{ 1, 2, 3, 4, 5, 6 }となる
Copyメソッドの代わりに、CopyToメソッドを使うこともできます。
Dim ary1 As Integer() = New Integer() {1, 2, 3} Dim ary2 As Integer() = New Integer() {4, 5, 6} Dim mergedArray As Integer() = New Integer(ary1.Length + ary2.Length - 1) {} ary1.CopyTo(mergedArray, 0) ary2.CopyTo(mergedArray, ary1.Length)
int[] ary1 = new int[] { 1, 2, 3 }; int[] ary2 = new int[] { 4, 5, 6 }; int[] mergedArray = new int[ary1.Length + ary2.Length]; ary1.CopyTo(mergedArray, 0); ary2.CopyTo(mergedArray, ary1.Length);
または、Array.Resizeで連結基の配列を拡大して、連結する配列のデータをArray.Copyでコピーするという方法もあります。Array.Resizeは.NET Framework 2.0以降で使用できます。Array.Resizeは内部で新しい配列を作成してArray.Copyでデータをコピーしているため、結局は一番初めに紹介した例とほぼ同じです。
以下にArray.Resizeを使用した例を示します。
Dim ary1 As Integer() = New Integer() {1, 2, 3} Dim ary2 As Integer() = New Integer() {4, 5, 6} Dim aryLen As Integer = ary1.Length 'ary1のサイズを拡大する Array.Resize(ary1, ary1.Length + ary2.Length) 'ary2のデータをコピーする Array.Copy(ary2, 0, ary1, aryLen, ary2.Length)
int[] ary1 = new int[] { 1, 2, 3 }; int[] ary2 = new int[] { 4, 5, 6 }; int aryLen = ary1.Length; //ary1のサイズを拡大する Array.Resize(ref ary1, ary1.Length + ary2.Length); //ary2のデータをコピーする Array.Copy(ary2, 0, ary1, aryLen, ary2.Length);
Array.Copyメソッドの代わりにBuffer.BlockCopyメソッドを使うと、処理速度が上がります。ただしBuffer.BlockCopyメソッドは.NET Framework 2.0以降でのみ使用でき、さらに、プリミティブ型の配列だけに使用できます。Bufferクラスが対応しているプリミティブ型は、Boolean、Char、SByte、Byte、Int16、UInt16、Int32、UInt32、Int64、UInt64、IntPtr、UIntPtr、Single、Doubleです。
Buffer.BlockCopyメソッドでは、コピーする位置をインデックスではなくオフセット位置で指定し、オフセット位置とコピーする長さをバイトで指定しなければならない点に注意が必要です。
以下にBuffer.BlockCopyメソッドを使った例を示します。
Dim ary1 As Integer() = New Integer() {1, 2, 3} Dim ary2 As Integer() = New Integer() {4, 5, 6} Dim mergedArray As Integer() = New Integer(ary1.Length + (ary2.Length - 1)) {} '型のサイズを取得する(Int32の場合は 4) Dim typeSize As Integer = System.Runtime.InteropServices.Marshal.SizeOf( _ ary1.[GetType]().GetElementType()) 'Buffer.BlockCopyでコピーする Buffer.BlockCopy(ary1, 0, mergedArray, 0, _ ary1.Length * typeSize) Buffer.BlockCopy(ary2, 0, mergedArray, _ ary1.Length * typeSize, ary2.Length * typeSize)
int[] ary1 = new int[] { 1, 2, 3 }; int[] ary2 = new int[] { 4, 5, 6 }; int[] mergedArray = new int[ary1.Length + ary2.Length]; //型のサイズを取得する(Int32の場合は 4) int typeSize = System.Runtime.InteropServices.Marshal.SizeOf( ary1.GetType().GetElementType()); //Buffer.BlockCopyでコピーする Buffer.BlockCopy(ary1, 0, mergedArray, 0, ary1.Length * typeSize); Buffer.BlockCopy(ary2, 0, mergedArray, ary1.Length * typeSize, ary2.Length * typeSize);
LINQが使えるのならば、Concatメソッドで連結することができます。これが使用できるのは.NET Framework 3.5以降で、参照設定に「System.Core.dll」を追加する必要があります。
以下に例を示します。
'Imports System.Linq 'がソースファイルの一番上に書かれているものとする 'マージする配列(コレクションでも可) Dim ary1 As Integer() = New Integer() {1, 2, 3} Dim ary2 As Integer() = New Integer() {4, 5, 6} 'Concatで連結して、ToArrayで配列にする Dim mergedArray As Integer() = ary1.Concat(ary2).ToArray()
//using System.Linq; //がソースファイルの一番上に書かれているものとする //マージする配列(コレクションでも可) int[] ary1 = new int[] { 1, 2, 3 }; int[] ary2 = new int[] { 4, 5, 6 }; //Concatで連結して、ToArrayで配列にする int[] mergedArray = ary1.Concat(ary2).ToArray();
yieldを利用してIEnumerable(T)を返すメソッドを作成する方法を紹介します。この方法は.NET Framework 2.0以降のC#で使えます。
ここでは2つのInteger型配列を連結する方法を例にします。まず次のようなメソッドを作成します。yield returnで配列の要素を順番に返しているだけです。
//2つの整数型配列を連結するメソッド IEnumerable<int> Merge(int[] ary1, int[] ary2) { foreach (int i in ary1) yield return i; foreach (int i in ary2) yield return i; }
このメソッドを利用して2つの配列を連結するには、次のようにします。
//連結する配列 int[] ary1 = new int[] { 1, 2, 3 }; int[] ary2 = new int[] { 4, 5, 6 }; //連結する int[] mergedArray = Merge(ary1, ary2).ToArray();
Unionメソッドの説明は「要素が重複しないようにして、複数の配列(またはコレクション)をマージ(和集合を作成)する」に移動しました。