C#における配列とコレクションの全解説
はじめに
C#には、多種多様な配列とコレクション型が存在し、それぞれが異なるユースケースに対応しています。本記事では、C#で利用される配列やコレクションについて網羅的に解説し、それぞれの特徴と使い分けについて詳しく説明します。
1. 配列 (Array)
C#の配列は、固定長のデータ構造で、同じ型の要素を連続してメモリに格納します。配列のサイズは一度作成すると変更できません。配列はゼロベースでインデックスを持ち、任意の要素にアクセスできます。
int[] numbers = new int[3] { 1, 2, 3 };
Console.WriteLine(numbers[0]); // 1
numbers[1] = 5;
Console.WriteLine(numbers[1]); // 5
配列は、シンプルで高速にアクセスできるため、固定サイズのデータやパフォーマンスが重要な場合に適しています。しかし、サイズ変更が必要な場面では、他の動的なコレクションが使われます。
2. ジャグ配列 (Jagged Array)
ジャグ配列は「配列の配列」として表現され、各配列が異なる長さを持つことができます。二次元以上の配列を作成する際に便利です。
int[][] jaggedArray = new int[2][];
jaggedArray[0] = new int[] { 1, 2 };
jaggedArray[1] = new int[] { 3, 4, 5 };
foreach (var array in jaggedArray)
{
foreach (var num in array)
{
Console.Write(num + " ");
}
Console.WriteLine();
}
ジャグ配列は、異なる長さの配列が必要な場合に適しており、行列計算などに利用されることがあります。
3. List<T>
List<T>
は、配列の動的なバージョンで、サイズの変更が可能です。要素を追加、削除できるため、サイズが動的に変わるデータを扱う場合に非常に便利です。
using System;
using System.Collections.Generic;
List<string> fruits = new List<string> { "Apple", "Banana" };
fruits.Add("Orange");
Console.WriteLine(fruits[2]); // Orange
fruits.Remove("Banana");
Console.WriteLine(fruits.Count); // 2
List<T>
は、ほぼすべてのケースで配列よりも柔軟であり、通常のコレクション操作で最もよく使われます。
4. Collection<T>
Collection<T>
は、List<T>
に似た動的なコレクションですが、カスタマイズ可能で、継承して独自の振る舞いを追加することが可能です。通常、List<T>
よりも柔軟な管理が必要な場合に使用します。
using System;
using System.Collections.ObjectModel;
Collection<string> collection = new Collection<string>();
collection.Add("Apple");
collection.Add("Banana");
collection.Remove("Apple");
5. ReadOnlyCollection<T>
ReadOnlyCollection<T>
は、読み取り専用のコレクションを提供します。内部的には他のコレクションをラップしており、要素のアクセスは許可されますが、変更はできません。APIの結果を外部に公開する際や、コレクションの不変性を保証するために使います。
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
List<string> list = new List<string> { "Apple", "Banana" };
ReadOnlyCollection<string> readOnlyList = new ReadOnlyCollection<string>(list);
// 読み取り専用
Console.WriteLine(readOnlyList[0]); // Apple
6. IReadOnlyList<T>
IReadOnlyList<T>
は、インデックス付きの読み取り専用リストを表すインターフェースです。これは、ReadOnlyCollection<T>
や他のコレクションに対して読み取り専用のアクセスを提供しますが、変更は許可されません。
7. IEnumerable<T>
IEnumerable<T>
は、データのシーケンスを表す基本的なインターフェースであり、foreach
ループで使用されます。要素を順次処理したり、遅延評価が可能な場合に利用します。
using System;
using System.Collections.Generic;
IEnumerable<int> GetNumbers()
{
yield return 1;
yield return 2;
yield return 3;
}
foreach (var num in GetNumbers())
{
Console.WriteLine(num);
}
8. IList<T>
IList<T>
は、インデックス付きコレクションを表すインターフェースで、要素の追加、削除、挿入などの操作が可能です。List<T>
や他のリスト系コレクションで使用されます。
9. 多次元配列 (Multidimensional Array)
C#の多次元配列は、固定サイズの行列やグリッドのようなデータ構造を表現するために使用されます。[,]
を使って定義します。
int[,] matrix = new int[3, 3]
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
Console.WriteLine(matrix[0, 1]); // 2
10. スパン (Span<T>)
Span<T>
は、メモリの連続した部分を表現する軽量な型です。低レベルのメモリ操作やバッファ管理で利用されますが、ガベージコレクションの負荷を抑えるため、パフォーマンスが非常に重要なシナリオで使われます。
Span<int> numbers = stackalloc int[] { 1, 2, 3 };
numbers[1] = 42;
Console.WriteLine(numbers[1]); // 42
まとめ
C#には、さまざまな配列とコレクションの型が存在し、用途に応じて使い分けることが重要です。Array
やList<T>
など、動的なコレクションが必要な場合もあれば、ReadOnlyCollection<T>
のように不変のデータ構造が必要な場合もあります。それぞれの型を理解し、適切な場面で使用することで、より効率的なコードが実現できます。