ArrayクラスのCopyメソッド/CopyToメソッド、BufferクラスのBlockCopyメソッド、LINQのConcatメソッドなどを使い、配列を連結する方法を解説する。
2つの配列を連結するには幾つかの方法がある。本稿ではその違いを整理して解説する。
特定のトピックをすぐに知りたいという方は以下のリンクを活用してほしい。
なお、利用できる.NET Frameworkのバージョンはさまざまであるが、本稿に掲載したサンプルコードをそのまま試すにはVisual Studio 2015以降が必要である。また、サンプルコードはコンソールアプリの一部であり、コードの冒頭に以下の宣言が必要となる。
using System;
using System.Collections.Generic;
using System.Linq;
using static System.Console;
Imports System.Console
また、サンプルコードでは次のコードに示すメソッドを呼び出している。
static void ShowAll(IEnumerable<int> collection)
=> WriteLine(string.Join(", ", collection.Select(i => i.ToString()).ToArray()));
Sub ShowAll(collection As IEnumerable(Of Integer))
WriteLine(String.Join(", ", collection.Select(Function(i) i.ToString()).ToArray()))
End Sub
新しい配列を作り、Arrayクラス(System名前空間)のCopyToメソッド/Copy静的メソッドを使って元の配列の内容をコピーする。.NET Framework 1.1から(すなわち全てのバージョンの.NET Frameworkで)利用できる。配列の内容はどんな型でもよい。
1次元配列の場合は、CopyToメソッドが使える(次のコード)。後述するCopy静的メソッドよりも引数が少なく、使い勝手がよい。
int[] array1 = { 1, 2, 3, };
int[] array2 = { 2, 4, 6, };
// 新しい配列を作る
int[] newArray = new int[array1.Length + array2.Length];
// 元の配列の内容を新しい配列へコピーする
array1.CopyTo(newArray, 0);
array2.CopyTo(newArray, array1.Length);
ShowAll(newArray);
// 出力:1, 2, 3, 2, 4, 6
Dim array1() As Integer = {1, 2, 3}
Dim array2() As Integer = {2, 4, 6}
' 新しい配列を作る
Dim newArray(array1.Length + array2.Length - 1) As Integer
' 元の配列の内容を新しい配列へコピーする
array1.CopyTo(newArray, 0)
array2.CopyTo(newArray, array1.Length)
ShowAll(newArray)
' 出力:1, 2, 3, 2, 4, 6
Copy静的メソッドを使えば、多次元配列でも連結できる(次のコード)。
int[,] array21 = { { 1, 2, 3, }, { 4, 5, 6,} };
int[,] array22 = { { 11, 12, 13, }, { 14, 15, 16, } };
// 新しい配列を作る
int[,] newArray2 = new int[4,3];
// 元の配列の内容を新しい配列へコピーする
Array.Copy(array21, newArray2, array21.Length);
Array.Copy(array22, 0, newArray2, array21.Length, array22.Length);
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 3; j++)
Write($"{newArray2[i,j]}, ");
WriteLine();
}
// 出力:
// 1, 2, 3,
// 4, 5, 6,
// 11, 12, 13,
// 14, 15, 16,
Dim array21(,) As Integer = {{1, 2, 3}, {4, 5, 6}}
Dim array22(,) = {{11, 12, 13}, {14, 15, 16}}
' 新しい配列を作る
Dim newArray2(3, 2) As Integer
' 元の配列の内容を新しい配列へコピーする
Array.Copy(array21, newArray2, array21.Length)
Array.Copy(array22, 0, newArray2, array21.Length, array22.Length)
For i As Integer = 0 To 3
For j As Integer = 0 To 2
Write($"{newArray2(i, j)}, ")
Next
WriteLine()
Next
' 出力:
' 1, 2, 3,
' 4, 5, 6,
' 11, 12, 13,
' 14, 15, 16,
なお、1次元配列かつその要素がプリミティブ型(数値/真偽値など)の場合には、Bufferクラス(System名前空間)のBlockCopyメソッドを使うと高速にコピーできる(次のコード)。
int[] array1 = { 1, 2, 3, };
int[] array2 = { 2, 4, 6, };
// 新しい配列を作る
int[] newArray = new int[array1.Length + array2.Length];
// 元の配列の内容を新しい配列へコピーする
int array1Length = Buffer.ByteLength(array1);
int array2Length = Buffer.ByteLength(array2);
Buffer.BlockCopy(array1, 0, newArray, 0, array1Length);
Buffer.BlockCopy(array2, 0, newArray, array1Length, array2Length);
ShowAll(newArray);
// 出力:1, 2, 3, 2, 4, 6
Dim array1() As Integer = {1, 2, 3}
Dim array2() As Integer = {2, 4, 6}
' 新しい配列を作る
Dim newArray(array1.Length + array2.Length - 1) As Integer
' 元の配列の内容を新しい配列へコピーする
Dim array1Length As Integer = Buffer.ByteLength(array1)
Dim array2Length As Integer = Buffer.ByteLength(array2)
Buffer.BlockCopy(array1, 0, newArray, 0, array1Length)
Buffer.BlockCopy(array2, 0, newArray, array1Length, array2Length)
ShowAll(newArray)
' 出力:1, 2, 3, 2, 4, 6
.NET Framework 2.0からは、ArrayクラスのResizeメソッドで1次元配列のサイズを拡大できる。1つ目の配列を拡大し、そこに2つ目の配列の内容をCopyToメソッドなどを使ってコピーして追加すれば、2つを連結した配列になる(次のコード)。
ただし、配列を拡大するといっても、内部的には新しい配列を作ってそこにコピーしている。前述した新しい配列を作る方法と、本質的には同じことである。
int[] array1 = { 1, 2, 3, };
int[] array2 = { 2, 4, 6, };
// 1つ目の配列を拡大する
Array.Resize(ref array1, array1.Length + array2.Length);
// 2つ目の配列の内容を1つ目の配列へコピーする
array2.CopyTo(array1, array1.Length - array2.Length);
ShowAll(array1);
// 出力:1, 2, 3, 2, 4, 6
Dim array1() As Integer = {1, 2, 3}
Dim array2() As Integer = {2, 4, 6}
' 1つ目の配列を拡大する
Array.Resize(array1, array1.Length + array2.Length)
' 2つ目の配列の内容を1つ目の配列へコピーする
array2.CopyTo(array1, array1.Length - array2.Length)
ShowAll(array1)
' 出力:1, 2, 3, 2, 4, 6
なお、Visual Basicでは、ReDimステートメントでも配列のサイズを変更できる(次のコード)。ReDimステートメントも、内部的には新しい配列を作っている。
Dim array1() As Integer = {1, 2, 3}
Dim array2() As Integer = {2, 4, 6}
' 1つ目の配列を拡大する
ReDim Preserve array1(array1.Length + array2.Length - 1)
' 2つ目の配列の内容を1つ目の配列へコピーする
array2.CopyTo(array1, array1.Length - array2.Length)
ShowAll(array1)
' 出力:1, 2, 3, 2, 4, 6
.NET Framework 3.5で導入されたLINQを使うと、1次元配列の連結がとても簡潔に書ける(次のコード)。メモリ効率も前述の方法とそん色ないので、.NET Framework 3.5以降ではLINQを使うこの方法がお勧めである。
int[] array1 = { 1, 2, 3, };
int[] array2 = { 2, 4, 6, };
// LINQで連結する
int[] concatenated = array1.Concat(array2).ToArray();
ShowAll(concatenated);
// 出力:1, 2, 3, 2, 4, 6
Dim array1() As Integer = {1, 2, 3}
Dim array2() As Integer = {2, 4, 6}
' LINQで連結する
Dim concatenated() As Integer = array1.Concat(array2).ToArray()
ShowAll(concatenated)
' 出力:1, 2, 3, 2, 4, 6
また、LINQでは、重複する要素を除外してマージすることも簡単である(次のコード)。
int[] array1 = { 1, 2, 3, };
int[] array2 = { 2, 4, 6, };
// LINQで重複を排除して連結する
int[] union = array1.Union(array2).ToArray();
ShowAll(union);
// 出力:1, 2, 3, 4, 6
Dim array1() As Integer = {1, 2, 3}
Dim array2() As Integer = {2, 4, 6}
' LINQで重複を排除して連結する
Dim union() As Integer = array1.Union(array2).ToArray()
ShowAll(union)
' 出力:1, 2, 3, 4, 6
なお、1つ目の配列からList<T>コレクション(System.Collections.Generic名前空間)を作り、List<T>クラスのAddRangeメソッドを使って2つ目の配列を連結し、再び配列に戻すという方法でも可能ではある。しかし、この方法はコードが長くなる上にメモリを余分に使うので、あまりお勧めではない(次のコード、C#のみで解説)。
int[] array1 = { 1, 2, 3, };
int[] array2 = { 2, 4, 6, };
// 1つ目の配列をLINQでList<T>に変換する
var list1 = array1.ToList();
// [確認]上で作成したList<T>オブジェクトは、元の配列とは別物
list1[0] = 100;
ShowAll(array1); // 出力:1, 2, 3
ShowAll(list1); // 出力:100, 2, 3
// →array1とlist1は別物。list1の分だけ余計にメモリを確保した
// List<T>オブジェクトの後ろに、2つ目の配列を連結する
list1.AddRange(array2);
// List<T>オブジェクトをLINQで配列に変換する
int[] result = list1.ToArray();
// [確認]上で作成した配列は、List<T>オブジェクトとは別物
list1[0] = -99;
ShowAll(list1); // 出力:-99, 2, 3, 2, 4, 6
ShowAll(result); // 出力:100, 2, 3, 2, 4, 6
// →list1とresultは別物。resultの分だけメモリをさらに確保した
1次元配列を連結するには、.NET Framework 3.5以降ならLINQを使うのが簡潔だ。それ以前では、新しい配列を作って元の配列をコピーするか、あるいは元の配列を拡張するかした後で、連結する配列をその後ろにコピーする。
プリミティブ型の1次元配列では、BufferクラスのBlockCopyメソッドを使うと高速にコピーできる。
多次元配列の場合は、新しい配列を作って、ArrayクラスのCopy静的メソッドを使う。
利用可能バージョン:.NET Framework 1.1以降(一部、2.0以降、または3.5以降)
カテゴリ:クラスライブラリ 処理対象:配列
使用ライブラリ:Arrayクラス(System名前空間)
使用ライブラリ:Bufferクラス(System名前空間)
使用ライブラリ:Enumerableクラス(System.Linq名前空間)
関連TIPS:配列のコピーを1行でするには?[C#/VB]
関連TIPS:配列の一部だけをコピーするには?[C#/VB]
関連TIPS:配列のサイズを変更するには?(Resize編)[2.0のみ、C#、VB]
関連TIPS:C#で配列を宣言するには?
関連TIPS:VB.NETで配列を宣言するには?
関連TIPS:構文:メソッドやプロパティをラムダ式で簡潔に実装するには?[C# 6.0/7.0]
関連TIPS:構文:クラス名を書かずに静的メソッドを呼び出すには?[C# 6.0]
関連TIPS:VB.NETでクラス名を省略してメソッドや定数を利用するには?
関連TIPS:数値を右詰めや0埋めで文字列化するには?[C#、VB]
Copyright© Digital Advantage Corp. All Rights Reserved.