CLRにおける配列の基本クラスです。
int[] array1 = new int[5]; Array array2 = Array.CreateInstance(typeof(int), 5); Type type1 = array1.GetType(); // System.Int32[] Type type2 = array2.GetType(); // System.Int32[] array1[3] = 10; array2.SetValue(10, 3); int r1 = array1[3]; int r2 = (int)array2.GetValue(3);
[SerializableAttribute] [ComVisibleAttribute(true)] public abstract class Array : ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable構文 - Array クラス (System) | MSDN
型 | プロパティ | 内容 |
---|---|---|
bool | IsFixedSize | Arrayが固定サイズかどうか |
bool | IsReadOnly | Arrayが読み取り専用かどうか |
bool | IsSynchronized | Arrayへのアクセスが同期されている (スレッドセーフである) かどうか。つねにfalse |
int | Length | Arrayのすべての次元内の要素の総数 |
long | LongLength | Arrayのすべての次元内の要素の総数 (64ビット整数) |
int | Rank | Arrayのランク (次元数) を取得する。たとえば1次元配列は1で、2次元は2 |
object | SyncRoot | Arrayへのアクセスを同期するために使用できるオブジェクト |
名前 | 説明 | |
---|---|---|
作成 | CreateInstance(Type, Int32) | Typeと長さを指定して、0から始まるインデックスを持つ1次元の配列を作成する |
CreateInstance(Type, Int32, Int32) | Typeと次元の長さを指定して、0から始まるインデックスを持つ2次元の配列を作成する | |
CreateInstance(Type, Int32, Int32, Int32) | Typeと次元の長さを指定して、0から始まるインデックスを持つ3次元の配列を作成する | |
CreateInstance(Type, Int32[]) | Typeと次元の長さを指定して、0から始まるインデックスを持つ多次元の配列を作成する | |
Empty<T>() | 空の配列を返す | |
初期化 | Initialize() | 値型の既定のコンストラクターを呼び出し、この値型の各要素を初期化する |
Clear(Array, Int32, Int32) | 配列内にある要素の範囲を、各要素の型の既定値に設定する | |
複製 | Clone() | Arrayの簡易コピーを作成する |
CopyTo(Array, Int32) | 1次元配列のすべての要素を、指定の1次元配列にコピーする | |
Copy(Array, Array, Int32) | 他の配列に、指定範囲の要素をコピーする | |
ConstrainedCopy(Array, Int32, Array, Int32, Int32) | 他の配列に、指定範囲の要素をコピーする。コピーが完全に成功しないならば、変更が適用されないことが保証される | |
AsReadOnly<T>(T[]) | 指定の配列をラップする、読み取り専用のラッパーを作成する | |
要素数 | GetLength(Int32) | 指定の次元にある要素の数を表す、32ビット整数を取得する |
GetLongLength(Int32) | 指定の次元にある要素の数を表す、64ビット整数を取得する | |
値の取得 | GetValue(Int32) | 1次元の配列内の、指定位置にある値を取得する |
GetValue(Int32, Int32) | 2次元の配列内の、指定位置にある値を取得する | |
GetValue(Int32, Int32, Int32) | 3次元の配列内の、指定位置にある値を取得する | |
GetValue(Int32[]) | 多次元の配列内の、指定位置にある値を取得する | |
値の設定 | SetValue(Object, Int32) | 1次元の配列内の指定位置にある要素に、値を設定する |
SetValue(Object, Int32, Int32) | 2次元の配列内の指定位置にある要素に、値を設定する | |
SetValue(Object, Int32, Int32, Int32) | 3次元の配列内の指定位置にある要素に、値を設定する | |
SetValue(Object, Int32[]) | 多次元の配列内の指定位置にある要素に、値を設定する | |
検索 | FindAll<T>(T[], Predicate<T>) | 指定条件に一致する、すべての要素を取得する |
Find<T>(T[], Predicate<T>) | 指定条件に一致する要素を検索し、最もインデックスの小さい要素を返す | |
FindLast<T>(T[], Predicate<T>) | 指定条件に一致する要素を検索し、最もインデックスの大きい要素を返す | |
FindIndex<T>(T[], Predicate<T>) | 指定条件に一致する要素を検索し、最もインデックスの小さい要素のインデックスを返す | |
FindLastIndex<T>(T[], Predicate<T>) | 指定条件に一致する要素を検索し、最もインデックスの大きい要素のインデックスを返す | |
IndexOf(Array, Object) | 指定のオブジェクトを検索し、1次元の配列でそのオブジェクトが最初に見つかった位置のインデックスを返す | |
LastIndexOf(Array, Object) | 指定のオブジェクトを検索し、1次元の配列でそのオブジェクトが最後に見つかった位置のインデックスを返す | |
BinarySearch(Array, Object) | 1次元の並べ替え済み配列全体の中から、特定の要素を検索する | |
Exists<T>(T[], Predicate<T>) | 指定の配列に、指定条件に一致する要素が含まれているかどうかを判断する | |
TrueForAll<T>(T[], Predicate<T>) | 配列内のすべての要素が、指定条件に一致するかどうかを調べる | |
並べ替え | Sort(Array) | Arrayの各要素のIComparable実装を使用して、1次元配列全体の要素を並べ替える |
Sort(Array, IComparer) | 1次元の配列内の要素を、指定のIComparerを使用して並べ替える | |
Sort(Array, Array, IComparer) | 2つの1次元配列オブジェクト (一方のオブジェクトがキーを格納し、他方のオブジェクトがそれらに対応する項目を格納する) を、最初の配列内のキーに基づき、指定のIComparerを使用して並べ替える | |
Reverse(Array) | 1次元の配列内の、要素のシーケンスを反転させる | |
変換 | ConvertAll<TInput, TOutput>(TInput[], Converter<TInput, TOutput>) | ある型の配列を、別の型の配列に変換する |
Resize<T>(T[], Int32) | 1次元の配列の要素数を、指定した新しいサイズに変更する | |
その他 | ForEach<T>(T[], Action<T>) | 指定の配列内の各要素に対して、指定された処理を実行する |
GetEnumerator() | IEnumeratorを得られる | |
GetLowerBound(Int32) | 配列内の指定の次元の、最初の要素のインデックスを取得する | |
GetUpperBound(Int32) | 配列内の指定の次元の、最後の要素のインデックスを取得する |
型の既定値を設定できます。
int[] a = new int[] { 1, 2, 3, 4, 5 };
Array.Clear(a, 1, 3); // 1, 0, 0, 0, 5
要素の範囲を省略したいならば、IListにキャストした上でArray.IList.Clear()を呼びます。Array.IList.Clear メソッド (System) | Microsoft Learn
.NET 6以降ならば、Array.Clear()で同様に処理できます。
int[] b = new int[] { 1, 2, 3, 4, 5 };
((IList)b).Clear(); // 0, 0, 0, 0, 0
配列を複製できるメソッドは3つあり、これらは複製できる範囲と適用可能な次元に違いがあります。
メソッド | 複製範囲 | 適用可能な次元 |
---|---|---|
Clone() | すべての要素 | 任意の次元 |
CopyTo() | 指定位置から末尾までの要素 | 1次元のみ |
Copy() | 指定位置から末尾までの要素、または指定位置から指定数の要素 | 任意の次元 |
これらのメソッドではすべてシャローコピー (Shallow copy) で処理されるため、参照が複製されます。c# - Deep Copy with Array - Stack Overflow
public object Clone()Array.Clone メソッド (System) | MSDN
int[] src = new int[] { 1, 2, 3 };
object dest = src.Clone(); // 1, 2, 3
public void CopyTo( Array array, // コピー先の配列 int index // コピーを開始するインデックス )Array.CopyTo メソッド (Array, Int32) (System) | MSDN Array.CopyTo メソッド (System) | MSDN
コピー先の要素が不足するとArgumentExceptionが投げられ、充足ならば元の値が残ります。
int[] src = new int[] { 1, 2, 3 }; int[] dest1 = new int[] { 9, 9, 9, 9 }; src.CopyTo(dest1, 1); // 9, 1, 2, 3 int[] dest2 = new int[] { 9, 9, 9, 9, 9 }; src.CopyTo(dest2, 1); // 9, 1, 2, 3, 9 int[] dest3 = new int[3]; src.CopyTo(dest3, 1); // ArgumentException「ターゲット配列の長さが足りません。destIndex、長さ、および配列の最小値を確認してください。」
public static void Copy( Array sourceArray, // コピー元の配列 Array destinationArray, // コピー先の配列 int length // コピーする要素の数 )Copy(Array, Array, Int32) - Array.Copy メソッド (System) | Microsoft Learn
配列の途中からコピーしたいならば、開始インデックスを指定できる形式を用います。
public static void Copy( Array sourceArray, // コピー元の配列 int sourceIndex, // コピーを開始するインデックス Array destinationArray, // コピー先の配列 int destinationIndex, // コピー先の配列に格納を開始するインデックス int length )Copy(Array, Int32, Array, Int32, Int32) - Array.Copy メソッド (System) | Microsoft Learn
int[] src = new int[] { 1, 2, 3 }; int[] dest1 = new int[] { 9, 9 }; Array.Copy(src, 1, dest1, 0, 2); // 2, 3 int[] dest2 = new int[] { 9, 9, 9 }; Array.Copy(src, 1, dest2, 0, 2); // 2, 3, 9 int[] dest3 = new int[1]; Array.Copy(src, 1, dest3, 0, 2); // ArgumentException「ターゲット配列の長さが足りません。destIndex、長さ、および配列の最小値を確認してください。」
多次元配列をコピーするときには、すべての要素が1次元に並んでいると見なしてsourceIndexなどのインデックスを指定します。
次のクラスが要素である配列を、複製する場合を考えます。
class MyClass { public int data; public MyClass(int data) { this.data = data; } }
MyClass[] src = { new MyClass(1), new MyClass(2) };
MyClass[] dest = (MyClass[])src.Clone();
src[0].data = 3;
Console.Write(dest[0].data); // 3
MyClass[] src = { new MyClass(1), new MyClass(2) };
MyClass[] dest = new MyClass[src.Length];
src.CopyTo(dest, 0);
src[0].data = 3;
Console.Write(dest[0].data); // 3
MyClass[] src = { new MyClass(1), new MyClass(2) };
MyClass[] dest = new MyClass[src.Length];
Array.Copy(src, dest, src.Length);
src[0].data = 3;
Console.Write(dest[0].data); // 3
Clone()とCopy()で、1次元配列と同様に複製できます。一方でCopyTo()は多次元に対応しないため、例外が発生します。
int[,] src = { { 1, 2, 3 }, { 4, 5, 6 } }; // Clone() int[,] dest1 = (int[,])src.Clone(); // CopyTo() int[,] dest2 = new int[src.GetLength(0), src.GetLength(1)]; src.CopyTo(dest2, 0); // System.ArgumentException 要求されたアクションに対しては、1 次元配列のみがサポートされます。 // Copy() int[,] dest3 = new int[src.GetLength(0), src.GetLength(1)]; Array.Copy(src, dest3, src.Length);
ジャグ配列の要素は配列のため、シャローコピーにより参照がコピーされることで、コピー先の配列への変更がコピー元へ影響します。
int[][] src = new int[][] { new int[] { 1, 2, 3 }, new int[] { 4, 5, 6 } }; int[][] dest = (int[][])src.Clone(); dest[1][1] = 10; // コピー先の配列を変更 Console.Write(src[1][1]); // 10 (コピー元の配列へ影響する)
// 多次元配列 の場合 int[,] src = { { 1, 2, 3 }, { 4, 5, 6 } }; int[,] dest = (int[,])src.Clone(); dest[1, 1] = 10; // コピー先の配列を変更 Console.Write(src[1, 1]); // 5 (コピー元の配列は影響されない)
Copy()では「System.RankException 指定された配列の次元数は同じでなければなりません。」として異なる次元へ複製できないため、Buffer.BlockCopy()でバイト単位で複製します。c# - Does Array.Copy work with multidimensional arrays? - Stack Overflow
int[,] src = { { 1, 2, 3 }, { 4, 5, 6 } }; // コピー元の2次元配列 int[] dest = new int[src.Length]; // コピー先の1次元配列 int count = src.GetLength(1) * sizeof(int); for (int i = 0; i < src.Rank; i++) { int offset = count * i; Buffer.BlockCopy(src, offset, dest, offset, count); }
一方でジャグ配列はその要素が配列のため、Copy()で処理できます。
int[][] src = new int[3][]; // コピー元の2次元配列 src[0] = new int[] { 1, 2, 3, 4 }; src[1] = new int[] { 5, 6 }; src[2] = new int[] { 7, 8, 9 }; int[] dest = new int[9]; // コピー先の1次元配列 Array.Copy(src[0], 0, dest, 0, 4); Array.Copy(src[1], 0, dest, 4, 2); Array.Copy(src[2], 0, dest, 6, 3);
汎用的には次のようにします。
int sum = 0; for (int i = 0; i < src.Length; i++) { sum += src[i].Length; } int[] dest = new int[sum]; for (int i = 0, offset = 0; i < src.Length; i++) { int length = src[i].Length; Array.Copy(src[i], 0, dest, offset, length); offset += length; }
指定オブジェクトに一致する要素を検索できます。
public static int IndexOf( Array array, // 検索対象の1次元配列 object value // 検索するオブジェクト )Array.IndexOf メソッド (Array, Object) (System) | MSDN
見つかった場合は一致した最初の要素のインデックス、さもなくば配列のインデックスの下限から-1したインデックスが返されます。
int[] a = new int[] { 1, 2, 3, 4, 5 }; int r1 = Array.IndexOf(a, 3); // 2 int r2 = Array.IndexOf(a, 10); // -1 (インデックスの下限0から-1した値)
比較はObject.Equals()メソッドで行われます。 arrayがT[]の配列ならばIndexOf<T>が用いられ、T.Equals()で行われます。
これをそのオブジェクトのEquals()で行うことを確実にしたいならば、IndexOf<T>を用います。この場合、比較はT.Equals()で行われます。
public static int IndexOf<T>( T[] array, T value )Array.IndexOf(T) メソッド (T[], T) (System) | MSDN
int[] a = new int[] { 1, 2, 3 };
int r = Array.IndexOf<int>(a, 3); // 2
これをより柔軟な条件で比較したいならば、FindIndex<T>(T[], Predicate<T>)を用います。なおList<T>には同様のメソッドとして、List<T>.IndexOf(T)があります。
指定条件に一致する要素を検索できます。
public static T Find<T>( T[] array, Predicate<T> match )Array.Find(T) メソッド (T[], Predicate(T)) (System) | MSDN
見つかった場合は一致した最初の要素、さもなくば型Tの既定値が返されます。
void MyClass()
{
int[] a = new int[] { 1, 2, 3, 4, 5 };
int r1 = Array.Find(a, Predicate); // 4
}
bool Predicate(int x)
{
return 3 < x;
}
ラムダ式を用いると、以下のようにも記述できます。
int r2 = Array.Find(a, (x) => { return 3 < x; }); // 4 int r3 = Array.Find(a, x => 3 < x ); // 4 int r4 = Array.Find(a, x => 10 < x ); // 0 (0はintの既定値)
IndexOf()とは異なり、返されるのはインデックスではなく要素です。
string[] str = new string[] { "a", "b", "c" };
string result = Array.Find(str, (x) => { return x == "b"; }); // "b"
検索対象が配列ではないならば、Enumerable.FirstOrDefault()で同様に検索できます。
配列と配列を比較し、その要素の並びが一致する位置を得るには文字列探索 (string searching) の手法を用います。
指定の配列に、指定条件に一致する要素が含まれているかどうかを確認できます。
public static bool Exists<T> ( T[] array, Predicate<T> match );Array.Exists<T>(T[], Predicate<T>) メソッド (System) | Microsoft Learn
int[] a = new int[] { 1, 2, 3 };
bool r = Array.Exists(a, x => x == 2); // true
内部的にはArray.FindIndex()を呼び出し、その戻り値が-1ではないことを確認するのと同じです。Exists - array.cs
配列内のすべての要素が、指定条件に一致するかどうかを確認できます。
bool r1 = Array.TrueForAll(new int[] { 1, 2, 3 }, x => x <= 2); // false bool r2 = Array.TrueForAll(new int[] { 1, 2, 2 }, x => x <= 2); // true
配列が空ならば、条件にかかわらずtrueが返されます。Returns - Array.TrueForAll<T>(T[], Predicate<T>) Method (System) | Microsoft Learn
bool r3 = Array.TrueForAll(new int[] { }, x => x == 1); // true
並べ替えの方法やその範囲によって、次のようにオーバーロードされています。
int[] a1 = { 3, 4, 6, 2, 4, 1 }; Array.Sort(a1); // 1, 2, 3, 4, 4, 6 int[] a2 = { 1, 2, 3, 4, 5 }; Array.Sort(a2, (x, y) => { return y - x; }); // 5, 4, 3, 2, 1 int[] a3 = { 1, 2, 3, 4, 5 }; Array.Sort(a3, (x, y) => { return (x == 3) ? -1 : 0; }); // 3, 1, 2, 4, 5
パーティションのサイズによって、使用されるアルゴリズムが異なります。
パーティションのサイズ | アルゴリズム |
---|---|
16以下 | 挿入ソート (insertion sort) |
2 * log Nを超える (Nは配列の範囲) | ヒープソート (heapsort) |
その他 | クイックソート (quicksort) |
// 要素数16 int[] a4 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; Array.Sort(a4, (x, y) => { return 0; }); // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 Array.Sort(a4, (x, y) => { return -1; }); // 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 a4 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; Array.Sort(a4, (x, y) => { return (x == 5) ? -1 : 0; }); // 5, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
// 要素数17 int[] a5 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; Array.Sort(a5, (x, y) => { return 0; }); // 1, 15, 14, 13, 12, 11, 10, 16, 9, 7, 6, 5, 4, 3, 2, 8, 17 a5 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; Array.Sort(a5, (x, y) => { return -1; }); // System.ArgumentExceptionが発生 // HResult : -2147024809 (0x80070057) // IComparer.Compare() メソッドから矛盾する結果が返されたため、並べ替えできません。値をそれ自体と比較したときに等しい結果にならないか、またはある値を別の値と繰り返し比較したときに異なる結果が生じます。 a5 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; Array.Sort(a5, (x, y) => { return (x == 5) ? -1 : 0; }); // 5, 1, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 4, 3, 2, 16, 17
// 要素数18 int[] a6 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; Array.Sort(a6, (x, y) => { return 0; }); // 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 17, 18
Win32のStrCmpLogicalW()メソッドを用いることで実現できます。StrCmpLogicalW function (shlwapi.h) - Win32 apps | Microsoft Learn
public class NaturalStringComparer : IComparer<string> { [SuppressUnmanagedCodeSecurity] [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] private static extern int StrCmpLogicalW(string psz1, string psz2); public int Compare(string x, string y) { return StrCmpLogicalW(x, y); } }sorting - Natural Sort Order in C# - Stack Overflow
これを用いると、次のように並べ替えられます。
string[] s = { "B10", "A2", "A11", "A1", "B2" }; Array.Sort(s); // "A1", "A11", "A2", "B10", "B2" Array.Sort(s, new NaturalStringComparer()); // "A1", "A2", "A11", "B2", "B10"
要素の順番を、反転させられます。
public static void Reverse( Array array, int index, int length )Array.Reverse メソッド (Array, Int32, Int32) (System) | MSDN
int[] array = new int[] { 1, 2, 3, 4, 5, 6 };
Array.Reverse(array, 1, 4); // { 1, 5, 4, 3, 2, 6 }
public static TOutput[] ConvertAll<TInput, TOutput>( TInput[] array, Converter<TInput, TOutput> converter )Array.ConvertAll(TInput, TOutput) Method (TInput[], Converter(TInput, TOutput)) (System) | MSDN
public delegate TOutput Converter<in TInput, out TOutput>( TInput input )Converter(TInput, TOutput) Delegate (System) | MSDN
static void Main() { double[] src = new double[] { 1.5, 2.5, 3.5 }; // 方法1: Converter<double, int> convert = new Converter<double, int>(DoubleToInt); int[] dst1 = Array.ConvertAll<double, int>(src, convert); // 方法2:一時変数をインライン化し、変換メソッドをdelegateで記述 int[] dst2 = Array.ConvertAll(src, new Converter<double, int>(delegate (double x) { return (int)x; })); // 方法3:delegateをラムダ式で記述 int[] dst3 = Array.ConvertAll(src, new Converter<double, int>((x) => { return (int)x; })); // 方法4:Convertクラスのメソッドで記述 int[] dst4 = Array.ConvertAll(src, Convert.ToInt32); } static int DoubleToInt(double x) { return (int)x; }c# - What is the actual use of Array.ConvertAll compared to e.g. looping through the array via foreach? - Stack Overflow
たとえばbyte配列からshort配列へは、次のようにも変換できます。bytearray - Convert byte array to short array in C# - Stack Overflow
byte[] src = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; short[] dst = new short[src.Length / 2]; Buffer.BlockCopy(src, 0, dst, 0, src.Length); Console.Write("{0:x4}", dst[0]); // 0201 Console.Write("{0:x4}", dst[1]); // 0403 Console.Write("{0:x4}", dst[2]); // 0605
配列内の各要素に対して、指定の処理を実行できます。
public static void ForEach<T>( T[] array, Action<T> action )Array.ForEach<T>(T[], Action<T>) メソッド (System) | Microsoft Learn
ListのForEach()とは異なり、これは静的メソッドです。
int[] a = new int[] { 1, 2, 3 }; // Array.ForEach(a, delegate (int x) { Console.Write(x); }); // ラムダ式によるに記述 Array.ForEach(a, x => Console.Write(x)); // Action<T>型のメソッドに各要素を渡すだけならば、そのメソッドを指定するだけで良い Array.ForEach(a, Console.Write);
メソッドだけを指定するとき、そのメソッドにConditional属性が付けられていると、ビルドによってはメソッドが存在しない可能性があるためにCS1618でエラーとなります。