C#で理解するListと配列の違いを徹底解説!

システム開発

リスト(List)と配列(Array)の違いに悩んだことはありませんか?プログラミングにおいてはどちらもデータを格納するための重要な要素ですが、それぞれに特性があり、適切に使い分けることで効率的なコードを書くことができます。本記事では、C#のListと配列の違いを分かりやすく解説し、どのような状況でどちらを選ぶべきかを明らかにします。さらに、メリットやデメリット、実際の使用例を交えながら、リストと配列の理解を深めるための知識を提供します。


配列(Array)の基本と特徴

C#の配列(Array)は、メモリの連続した領域にデータを格納する固定長のデータ構造です。プログラムのパフォーマンスを最適化するために、特定の用途では非常に有効な選択肢となります。

主な特徴

  1. 固定長

    配列を作成すると、そのサイズは変更できません。例えば、int[5] のように宣言すると、要素数5の配列が確保され、それ以上増やしたり減らしたりすることはできません。

  2. 高速なアクセス

    インデックスを使って直接データにアクセスできるため、ランダムアクセスのパフォーマンスが優れています。

  3. 静的なメモリ管理

    配列は宣言時に確保されるため、メモリの管理がしやすく、ガベージコレクション(GC)の影響を受けにくいです。

メリット

  • メモリ使用量が予測しやすい

    宣言時に確保されるため、動的なメモリ割り当てを伴うList<T>と比較して管理が容易です。

  • 高速なアクセス

    インデックスを使用してO(1)の時間計算量で要素にアクセス可能なため、パフォーマンス重視の処理に適しています。

デメリット

  • サイズ変更ができない

    配列のサイズは初期化時に固定されるため、途中で要素数を増減できません。

  • 要素の追加・削除が難しい

    中間の要素を削除したい場合には、残りの要素を詰める処理が必要になります。また、新しい要素を追加したい場合には、新たな配列を作り直す必要があります。

配列の基本的な使い方(コード例)

int[] numbers = new int[3]; // サイズが3の配列を作成
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;

Console.WriteLine(numbers[1]); // 出力: 2

ポイント:

  • 配列のサイズは new int[3] のように指定する必要があります。
  • 要素は numbers[index] のようにアクセスします。
  • サイズ変更ができないため、途中で要素を追加することはできません。

Listの基本と特徴

C#のList<T>は、サイズを動的に変更できる便利なデータ構造です。配列(Array)と異なり、要素の追加・削除が容易であり、高レベルなAPIを活用できる点が大きな特徴です。

主な特徴

  1. 可変長

    List<T>は、要素の追加・削除が自由に行えます。配列のように固定長である必要がなく、要素数が不確定な場合に便利です。

  2. 高レベルAPIを提供

    Add(), Remove(), Insert(), Contains(), Find() など、多くの便利なメソッドが標準で用意されています。

  3. 動的なメモリ管理

    必要に応じて内部的に配列サイズを増やしながらデータを管理します。そのため、手動でサイズを指定する必要がありません。

メリット

  • 要素の追加・削除が簡単

    List<T>なら、Add()メソッドで簡単に要素を追加でき、Remove()で削除も可能です。

  • サイズを事前に指定する必要がない

    配列と異なり、プログラム実行中に要素数を自由に増減できます。

  • LINQなどの高機能な操作が可能

    Where(), Select(), OrderBy() など、強力なLINQクエリを活用できます。

デメリット

  • メモリ使用量が増える可能性がある

    内部的に配列を拡張しながら管理するため、不要なメモリ割り当てが発生する可能性があります。

  • 大量の要素を追加するとパフォーマンスに影響

    List<T>は内部的に配列を管理し、一定のサイズに達すると倍増して新しい配列を作成します。そのため、大量の要素を追加するとパフォーマンスに影響が出ることがあります。

Listの基本的な使い方(コード例)

csharp
コピーする編集する
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int>(); // Listを初期化
        numbers.Add(1);
        numbers.Add(2);
        numbers.Add(3);

        Console.WriteLine(numbers[1]); // 出力: 2

        numbers.Remove(2); // 値2を削除
        numbers.Add(4);

        foreach (var num in numbers)
        {
            Console.WriteLine(num);
        }
    }
}

ポイント:

  • Add() で要素を追加できます。
  • Remove() で指定した値を削除できます。
  • foreach ループを使って簡単に要素を処理できます。

Listと配列の違いを比較表で解説

C#のList<T>Array(配列)は、どちらもデータを格納するための構造ですが、それぞれの特性が異なります。以下の表で違いを比較し、どのような場面でどちらを選ぶべきかを明確にします。

特徴 配列(Array) リスト(List<T>)
サイズ 固定長(変更不可) 可変長(動的に変更可能)
メモリ管理 静的(宣言時に確保) 動的(必要に応じて拡張)
要素の追加・削除 不可(新しい配列を作り直す必要あり) Add(), Remove() で容易に可能
アクセス速度 高速(インデックスアクセスがO(1)) インデックスアクセスは高速だが、サイズ変更時の処理が発生することがある
メソッドの豊富さ 基本的な操作のみ Add(), Remove(), Find(), Sort(), LINQ など多数
メモリ使用量 必要最小限 余裕をもってメモリを確保するため増加する場合あり
適した用途 高速処理が必要、要素数が決まっている場合 要素の追加・削除が多く、柔軟な操作が必要な場合
パフォーマンス 非常に高速(サイズが決まっている場合は最適) サイズ変更が発生するとパフォーマンスに影響がある場合あり
LINQのサポート ほぼなし(Arrayクラスのメソッドは少ない) List<T>はLINQを使った操作が可能

ポイントまとめ

  • 固定サイズなら配列(Array)を使用→ 高速なアクセスとメモリ効率が求められる場合に最適。
  • 可変サイズならList<T>を使用→ 要素の追加・削除が多く、柔軟なデータ操作が必要な場合に適している。

配列とListを使う場面の具体例

C#では、配列(Array)リスト(List<T>)はそれぞれ異なる用途に適しています。どちらを使うべきか迷ったときの判断基準として、具体的な使用場面を紹介します。

配列を使うべきケース

配列(Array)は、要素数が固定されている場合や、高速アクセスが求められる場面で使用されます。

1. 要素数が事前に決まっている場合

配列は固定長のため、最初からデータ数が決まっている場合に適しています。

例:曜日の一覧(変更不要)

string[] daysOfWeek = { "日", "月", "火", "水", "木", "金", "土" };
Console.WriteLine(daysOfWeek[2]); // 出力: 火

曜日のように、あらかじめ要素数が決まっていて変更する必要がないデータには配列が適しています。

2. 高速なデータアクセスが求められる場合

配列はインデックスアクセス(O(1))が可能なため、数値計算や画像処理など、頻繁にデータにアクセスする場面で有効です。

例:大量のデータを扱う計算処理

int[] numbers = new int[1000000]; // 100万個の整数を格納
for (int i = 0; i < numbers.Length; i++)
{
    numbers[i] = i * 2; // 高速なインデックスアクセス
}

大量の数値データを扱う場合、リストよりも配列の方がメモリ効率と処理速度が良い場合があります。

3. メモリ使用量を最適化したい場合

List<T>は内部で配列を管理し、必要に応じてメモリを再確保するため、余分なメモリを消費することがあります。一方、配列は最初に確保されたサイズのメモリのみを使用するため、メモリ効率が良いです。

例:組み込みシステムやリソースが限られた環境

byte[] buffer = new byte[1024]; // 1KBの固定バッファ

リソースが限られた環境(組み込みシステムなど)では、不要なメモリ確保を避けるために配列を使用することが一般的です。

Listを使うべきケース

List<T>は、要素数が実行時に変化する場合や、追加・削除を頻繁に行う場面で便利です。

1. 要素数が不確定で、追加・削除が発生する場合

実行時にデータが増減するような場合には、List<T>が適しています。

例:ユーザーが入力するデータの格納

List<string> names = new List<string>();
names.Add("Alice");
names.Add("Bob");
names.Remove("Alice"); // Aliceを削除

foreach (var name in names)
{
    Console.WriteLine(name);
}

リストなら、Add()Remove() などのメソッドを活用して簡単に要素を操作できます。

2. LINQを活用したデータ操作を行う場合

List<T>は、Where(), Select(), OrderBy() などのLINQメソッドを使うことで、簡単にデータ操作が可能です。

例:条件を満たすデータを抽出

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();

foreach (var num in evenNumbers)
{
    Console.WriteLine(num); // 出力: 2, 4, 6, 8, 10
}

このように、List<T>を使うとデータのフィルタリングや加工が簡単に行えます。

3. 外部データを扱う場合(ファイル・データベース・API)

データの量が事前にわからない場合はList<T>が適しています。

例:ファイルの各行をリストに格納

List<string> lines = new List<string>(System.IO.File.ReadAllLines("data.txt"));
lines.Add("新しいデータ"); // 追加可能

配列ではサイズを固定しなければなりませんが、List<T>なら可変なのでデータの増減に対応しやすくなります。

配列とListの使い分けポイント

選択基準 配列(Array) リスト(List<T>)
要素数が決まっているか 事前に確定している 不確定で変動する
要素の追加・削除 ほぼ不可 Add()Remove() で簡単に操作可能
パフォーマンス(アクセス速度) 高速(O(1)) 追加・削除時のコストがかかる
メモリ使用量 最小限 追加時にメモリを再確保するため増加する可能性あり
データの操作性 限られたメソッドのみ LINQや高度なメソッドが利用可能
用途 数値計算・画像処理・組み込み系 ユーザー入力、動的データ、データフィルタリング

配列とListのコード例で理解を深める

C#の配列(Array)リスト(List<T>)は、どちらもデータを格納するための基本的なデータ構造ですが、使い方や特性が異なります。ここでは、それぞれのコード例を示しながら、実際の使い方を理解していきましょう。

1. 配列(Array)のコード例

配列は固定サイズで、要素を直接インデックスで管理するシンプルなデータ構造です。

配列の基本的な操作

using System;

class Program
{
    static void Main()
    {
        // サイズ3の整数配列を作成
        int[] numbers = new int[3];

        // 配列に値を代入
        numbers[0] = 10;
        numbers[1] = 20;
        numbers[2] = 30;

        // 配列の値を表示
        Console.WriteLine(numbers[1]); // 出力: 20

        // 配列のループ処理
        for (int i = 0; i < numbers.Length; i++)
        {
            Console.WriteLine(numbers[i]);
        }
    }
}

ポイント:

  • numbers[1] のように、インデックスを指定して値にアクセス可能。
  • for ループを使って、すべての要素を処理できる。
  • サイズを変更することはできない(要素を追加・削除不可)。

配列の初期化と要素の一括代入

int[] numbers = { 1, 2, 3, 4, 5 };

foreach (var num in numbers)
{
    Console.WriteLine(num);
}
  • 配列は {} を使って直接値を代入することができる。

多次元配列(2D配列)

int[,] matrix = new int[2, 2] { { 1, 2 }, { 3, 4 } };
Console.WriteLine(matrix[1, 0]); // 出力: 3
  • [,] を使うと2D配列を作成できる。

2. List<T>(リスト)のコード例

List<T> は可変長で、要素の追加・削除が簡単なデータ構造です。

Listの基本的な操作

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Listを初期化
        List<int> numbers = new List<int>();

        // 要素の追加
        numbers.Add(10);
        numbers.Add(20);
        numbers.Add(30);

        // 要素の取得
        Console.WriteLine(numbers[1]); // 出力: 20

        // 要素の削除
        numbers.Remove(20);

        // ループ処理
        foreach (var num in numbers)
        {
            Console.WriteLine(num);
        }
    }
}

ポイント:

  • .Add(値) で要素を追加できる。
  • .Remove(値) で特定の要素を削除可能。
  • foreach を使って簡単にループ処理ができる。

Listの便利な操作

List<string> names = new List<string> { "Alice", "Bob", "Charlie" };

// 要素の追加
names.Add("David");

// 要素の検索
bool exists = names.Contains("Alice"); // true

// インデックスを指定して削除
names.RemoveAt(1); // "Bob" を削除

// ソート
names.Sort();

foreach (var name in names)
{
    Console.WriteLine(name);
}
  • .Contains() を使って要素の存在確認ができる。
  • .RemoveAt(index) で特定の位置の要素を削除可能。
  • .Sort() で昇順ソートができる。

LINQを使ったListの操作

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        // 偶数のリストを取得
        var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();

        foreach (var num in evenNumbers)
        {
            Console.WriteLine(num); // 出力: 2, 4, 6, 8, 10
        }
    }
}
  • .Where() を使って条件に合う要素を抽出できる。
  • .ToList() で結果をリストとして取得可能。

3. 配列とListの違いを比較するコード

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // 配列を作成
        int[] arrayNumbers = new int[3] { 1, 2, 3 };
        Console.WriteLine("配列の2番目の要素: " + arrayNumbers[1]); // 出力: 2

        // Listを作成
        List<int> listNumbers = new List<int> { 1, 2, 3 };
        listNumbers.Add(4);
        listNumbers.Remove(2);

        Console.WriteLine("Listの2番目の要素: " + listNumbers[1]); // 出力: 3

        // 配列のループ処理
        Console.WriteLine("配列の要素:");
        foreach (var num in arrayNumbers)
        {
            Console.WriteLine(num);
        }

        // Listのループ処理
        Console.WriteLine("Listの要素:");
        foreach (var num in listNumbers)
        {
            Console.WriteLine(num);
        }
    }
}

このコードのポイント

  • 配列はサイズを変更できない (arrayNumbers は固定サイズ)。
  • List<int>.Add() で要素を追加、.Remove() で削除ができる。
  • どちらも foreach を使って簡単にループ処理が可能。

配列とListの使い分けポイント

C#において、配列(Array)リスト(List<T>)はそれぞれ異なる特性を持ち、適した場面が異なります。どちらを使うべきか迷ったときは、以下のポイントを基準に選択しましょう。

配列(Array)を使うべきケース

配列は、サイズが決まっている場合や、高速なデータアクセスが求められる場合に適しています。

事前に要素数が決まっている場合

  • 例:曜日の一覧、固定データのリスト、構造が変わらないデータ
string[] daysOfWeek = { "日", "月", "火", "水", "木", "金", "土" };

📌 なぜ配列?

→ サイズが変わらないため、List<T>を使うメリットが少ない。

高速なデータアクセスが必要な場合

  • 例:数値計算、画像処理、大量データの高速処理
int[] numbers = new int[1000000];
for (int i = 0; i < numbers.Length; i++)
{
    numbers[i] = i * 2; // 高速アクセス
}

📌 なぜ配列?

→ インデックスアクセスが O(1) のため、ランダムアクセスが速い。

メモリ使用量を抑えたい場合

  • 例:組み込みシステム、リソースが限られた環境
byte[] buffer = new byte[1024]; // 1KBの固定バッファ

📌 なぜ配列?

List<T>は内部的に配列を拡張するため、メモリ消費が増える可能性がある。

多次元配列を扱う場合

  • 例:行列計算、ゲームのマップデータ
int[,] matrix = new int[3, 3] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
Console.WriteLine(matrix[1, 1]); // 出力: 5

📌 なぜ配列?

List<T>ではList<List<int>>のようなネスト構造が必要になり、扱いが複雑になる。

List<T>(リスト)を使うべきケース

List<T>は、要素の追加・削除が頻繁に発生する場合や、動的にサイズが変わるデータを扱う場合に適しています。

要素数が不確定で変動する場合

  • 例:ユーザー入力データ、データベースのレコード取得
List<string> names = new List<string>();
names.Add("Alice");
names.Add("Bob");
names.Remove("Alice");

📌 なぜList?

Add()Remove() を使って簡単に操作できる。

データのフィルタリングやソートをしたい場合

  • 例:LINQを活用したデータ操作
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();

📌 なぜList?

→ LINQを使ったデータ操作が容易。

動的にデータを追加・削除する場合

  • 例:ファイルの読み込み、動的なデータ管理
List<string> lines = new List<string>(System.IO.File.ReadAllLines("data.txt"));
lines.Add("新しいデータ");
lines.RemoveAt(0);

📌 なぜList?

Arrayだとサイズ変更ができないため、List<T>の方が適している。

コレクション操作が頻繁に必要な場合

  • 例:Sort()Find()
List<int> scores = new List<int> { 90, 80, 100, 70 };
scores.Sort();
int maxScore = scores.Max();

📌 なぜList?

List<T>には便利なメソッドが豊富。

配列とListの使い分けの判断基準

判断基準 配列(Array) List<T>
サイズが固定か? 固定サイズなら配列 可変サイズならList
要素の追加・削除が必要か? 不要なら配列 必要ならList
メモリ効率を優先するか? 優先する場合は配列 メモリ消費が増える可能性あり
高速なアクセスが必要か? インデックスアクセスが多いなら配列 操作の自由度を優先するならList
LINQを使いたいか? 使えない(基本操作のみ) 使える(Where, Select, OrderBy など)
多次元データを扱うか? [,] で簡単に管理可能 List<List<T>> で複雑になりがち
用途 数値計算、固定データ、リソース管理 ユーザー入力、データベース、ファイル処理

まとめ

C#の配列(Array)リスト(List<T>)は、どちらもデータを格納する基本的なデータ構造ですが、それぞれ特性や用途が異なります。本記事では、両者の違いや使い分けのポイントについて詳しく解説しました。

1. 配列(Array)とList<T>の特徴の比較

特徴 配列(Array) List<T>
サイズ 固定長(変更不可) 可変長(追加・削除可能)
メモリ管理 静的(宣言時に確保) 動的(必要に応じて拡張)
要素の追加・削除 できない(新しい配列を作り直す必要あり) .Add(), .Remove() で容易に可能
アクセス速度 高速(O(1)) 高速だが、サイズ変更時のコストが発生することがある
メソッドの豊富さ 基本的な操作のみ .Sort(), .Find(), .Where() など便利なメソッドが豊富
メモリ使用量 必要最小限 追加時に余分なメモリを確保する可能性あり
適した用途 高速処理が必要、要素数が決まっている場合 要素の追加・削除が多く、柔軟なデータ操作が必要な場合
LINQのサポート ほぼなし(基本操作のみ) List<T>はLINQを活用可能

2. 配列を使うべきケース

要素数が事前に決まっている場合

→ 曜日リスト、固定データ、メモリ効率を重視するシステム

高速なデータアクセスが求められる場合

→ 数値計算、大量データの処理、組み込みシステム

多次元データを扱う場合

→ 画像処理、行列演算、マップデータ管理

3. List<T>を使うべきケース

要素数が変動する場合

→ ユーザー入力データ、動的なデータ管理

要素の追加・削除を頻繁に行う場合

→ ファイルデータの読み込み、データベースのレコード管理

LINQを活用したデータ操作を行いたい場合

Where(), Select(), OrderBy() などの便利なメソッドを使う処理

4. 配列とListの使い分けの判断基準

  • 固定サイズなら → 配列(Array)
  • 可変サイズなら → List<T>
  • パフォーマンス(高速アクセス)が重要なら → 配列
  • データの追加・削除が必要なら → List<T>
  • メモリ効率を重視するなら → 配列
  • LINQや便利なメソッドを使いたいなら → List<T>

5. 結論

C#において、配列(Array)リスト(List<T>)は用途によって適切に使い分ける必要があります。

基本的な判断基準としては、固定サイズなら配列、可変サイズならList<T>を選ぶのが適切です。

状況に応じて最適なデータ構造を選択し、効率的なプログラミングを心がけましょう!

コメント

タイトルとURLをコピーしました