【C#】LINQのWhereメソッドで条件に一致する要素を抽出する方法:インデックス活用まで

目次

コレクションのフィルタリング処理

C#で配列やList<T>などのコレクションから、特定の条件を満たす要素だけを取り出したい場合、LINQ(Language Integrated Query)のWhereメソッドを使用するのが最も標準的な方法です。

foreachループとif文を組み合わせて抽出することも可能ですが、Whereメソッドを使用することで、フィルタリングのロジックを宣言的かつ簡潔に記述できます。

この記事では、Whereメソッドの基本的な使い方と、要素の「インデックス(順番)」を条件に加える応用的な使い方について解説します。


基本的な条件による抽出

Whereメソッドは、引数として「条件式(述語)」を受け取ります。コレクションの各要素に対してこの条件式が評価され、結果がtrueとなる要素のみを含む新しいシーケンス(IEnumerable<T>)が返されます。

コード例:在庫のある商品の抽出

商品リストから、在庫数が1以上で、かつ価格が一定以下の商品を抽出する例です。

using System;
using System.Collections.Generic;
using System.Linq; // LINQを使用するために必須

public class Product
{
    public string Name { get; set; }
    public int Price { get; set; }
    public int Stock { get; set; }
}

public class WhereBasicExample
{
    public static void Main()
    {
        // 商品データのリスト
        var products = new List<Product>
        {
            new Product { Name = "ゲーミングマウス", Price = 8000, Stock = 15 },
            new Product { Name = "メカニカルキーボード", Price = 15000, Stock = 0 }, // 在庫切れ
            new Product { Name = "USBハブ", Price = 2000, Stock = 30 },
            new Product { Name = "モニターアーム", Price = 5000, Stock = 5 },
            new Product { Name = "Webカメラ", Price = 4500, Stock = 0 } // 在庫切れ
        };

        // 条件: 在庫 (Stock) が 1 以上、かつ 価格 (Price) が 10000 未満
        // Where メソッドにラムダ式で条件を記述する
        var availableProducts = products.Where(p => p.Stock > 0 && p.Price < 10000);

        Console.WriteLine("--- 条件に一致する商品 ---");
        foreach (var item in availableProducts)
        {
            Console.WriteLine($"商品名: {item.Name}, 価格: {item.Price}円");
        }
    }
}

出力結果:

--- 条件に一致する商品 ---
商品名: ゲーミングマウス, 価格: 8000円
商品名: USBハブ, 価格: 2000円
商品名: モニターアーム, 価格: 5000円

インデックス(要素番号)を利用した抽出

Whereメソッドには、要素そのものだけでなく、その要素の**インデックス(何番目の要素か)**を使用できるオーバーロード(別バージョンのメソッド)が存在します。

構文: collection.Where((item, index) => 条件式)

  • item: 現在の要素
  • index: 現在の要素のインデックス(0から始まります)

これを利用すると、「偶数番目の要素だけを取得する」や「先頭の数件を除外して判定する」といったロジックを記述できます。

コード例:偶数月のデータのみを抽出

1月から12月までの売上データがある配列から、偶数月(2月、4月…)かつ売上が目標を超えている月を抽出する例です。配列のインデックスは0から始まるため、インデックスが奇数(1, 3, 5…)の場所が、実際には2月、4月、6月(偶数月)に相当します。

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

public class WhereIndexExample
{
    public static void Main()
    {
        // 1月から12月までの月間売上データ
        int[] monthlySales = 
        { 
            120, 150, 90, 200, 110, 
            300, 140, 160, 95, 210, 
            180, 250 
        };

        // 条件: 
        // 1. 偶数月であること (index は 0 始まりなので、index が奇数のときが偶数月)
        // 2. 売上が 150 以上であること
        var targetSales = monthlySales.Where((sales, index) => 
        {
            bool isEvenMonth = (index % 2 != 0); // 1, 3, 5... (2月, 4月, 6月...)
            return isEvenMonth && sales >= 150;
        });

        Console.WriteLine("--- 条件に一致する売上データ ---");
        foreach (var sales in targetSales)
        {
            Console.WriteLine($"売上: {sales}");
        }
    }
}

出力結果:

--- 条件に一致する売上データ ---
売上: 150
売上: 200
売上: 300
売上: 160
売上: 210
売上: 250

インデックス1(2月)の150、インデックス3(4月)の200などが抽出されています。


遅延実行(Deferred Execution)について

LINQのWhereメソッドの重要な特性として、「遅延実行」があります。

Whereメソッドを呼び出した時点では、フィルタリング処理は実行されません。戻り値であるクエリ(IEnumerable<T>)をforeachループで回した時や、ToList()ToArray()などを呼び出して実体化させた瞬間に、初めてフィルタリングが実行されます。

var numbers = new List<int> { 1, 2, 3 };
var query = numbers.Where(n => n > 1); // ここではまだ実行されない

numbers.Add(4); // リストに要素を追加

// ここで初めて実行されるため、後から追加した '4' も結果に含まれる
foreach (var n in query) 
{
    Console.WriteLine(n); // 2, 3, 4 が出力される
}

この特性を理解しておくことは、データの整合性を保つ上で非常に重要です。


まとめ

  • Where(x => ...): コレクションから条件を満たす要素を抽出する基本的な方法です。
  • Where((x, index) => ...): 要素の値だけでなく、インデックス(位置)も条件に含めることができます。
  • 遅延実行: クエリは定義時ではなく、列挙時(foreachなど)に実行されます。

WhereメソッドはLINQの中でも最も頻繁に使用されるメソッドの一つです。インデックスを活用する方法も含めて習得することで、より柔軟なデータ操作が可能になります。

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

この記事を書いた人

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

目次