【C#】LINQのElementAtとElementAtOrDefault:指定位置(インデックス)の要素を取得する方法

目次

LINQクエリ結果へのインデックスアクセス

C#で配列やList<T>を扱う場合、array[0]のようにインデクサ([])を使って特定の位置にある要素にアクセスするのが一般的です。

しかし、LINQのメソッド(OrderByWhereなど)が返す結果はIEnumerable<T>型であり、この型はインデクサ([])をサポートしていません。そのため、クエリ結果をToArray()などで配列に変換せずに、直接「N番目の要素」を取得したい場合には、LINQのElementAtメソッドを使用します。

この記事では、ElementAtメソッドの使い方と、範囲外アクセス時の例外を回避するElementAtOrDefaultメソッドについて解説します。


ElementAt(int index) メソッド

ElementAtメソッドは、シーケンス内の指定されたインデックス(0から始まる)にある要素を返します。

コード例:ソート後の特定順位を取得

整数のリストを昇順に並べ替え(ソート)、その中から「3番目に小さい値(インデックス 2)」を取得する例です。

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

public class ElementAtExample
{
    public static void Main()
    {
        // ランダムな数値リスト
        var scores = new List<int> { 85, 42, 99, 60, 73, 100 };

        // 1. スコアを昇順(小さい順)に並べ替え
        // 2. ElementAt(2) で「3番目」の要素を取得
        // (ソート後: 42, 60, 73, 85, 99, 100)
        int thirdLowestScore = scores.OrderBy(n => n).ElementAt(2);

        Console.WriteLine($"ソート前のリスト: {string.Join(", ", scores)}");
        Console.WriteLine($"3番目に小さいスコア: {thirdLowestScore}");
    }
}

出力結果:

ソート前のリスト: 85, 42, 99, 60, 73, 100
3番目に小さいスコア: 73

注意点:ArgumentOutOfRangeException

ElementAtメソッドは、指定したインデックスが負の数であったり、要素数以上であったりした場合、ArgumentOutOfRangeException という例外をスローしてプログラムを停止させます。

要素数が不確定な場合は、事前に.Count()で要素数を確認するか、次項のElementAtOrDefaultを使用する必要があります。


ElementAtOrDefault(int index) メソッド

ElementAtOrDefaultメソッドは、指定したインデックスが範囲外であった場合に例外をスローせず、その型の**既定値(デフォルト値)**を返します。

  • 参照型(stringなど): null
  • 数値型(intなど): 0

コード例:範囲外アクセスの安全な処理

商品リストから特定の要素を取得しようとし、存在しない場合でも安全に処理を続行する例です。

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

public class ElementAtOrDefaultExample
{
    public static void Main()
    {
        var products = new List<string> { "Keyboard", "Mouse", "Monitor" };

        // インデックス 10 は存在しない(範囲外)
        // ElementAt なら例外が発生するが、ElementAtOrDefault なら null が返る
        string? item = products.ElementAtOrDefault(10);

        if (item != null)
        {
            Console.WriteLine($"取得した商品: {item}");
        }
        else
        {
            Console.WriteLine("指定された位置に商品は存在しません。");
        }

        // null合体演算子 (??) との組み合わせが便利
        string displayItem = products.ElementAtOrDefault(5) ?? "(該当なし)";
        Console.WriteLine($"表示: {displayItem}");
    }
}

出力結果:

指定された位置に商品は存在しません。
表示: (該当なし)

パフォーマンスに関する考慮

ElementAtメソッドは、対象のコレクションがList<T>や配列のように「インデックスによるランダムアクセス」をサポートしている場合、最適化されて高速に動作します。

しかし、Whereメソッドの結果など、インデックスを持たないシーケンス(IEnumerable<T>)に対して使用した場合、先頭から指定された位置まで順番に要素をたどる(カウントする)処理が発生します。

そのため、巨大なシーケンスに対して大きなインデックスを指定してElementAtを繰り返し呼び出すと、処理速度が低下する可能性があります。


まとめ

  • ElementAt(index): 指定位置の要素を取得します。範囲外の場合は例外が発生します。要素が必ず存在すると確信できる場合に使用します。
  • ElementAtOrDefault(index): 指定位置の要素を取得します。範囲外の場合は**既定値(nullなど)**が返されます。要素数が不明確な場合や、安全性を優先する場合に使用します。

配列の [] と同様の感覚で使えますが、LINQクエリの結果(IEnumerable<T>)に対して直接適用できる点が大きなメリットです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次