【C#】LINQ Selectメソッドでデータを変換・射影する方法:匿名型やインデックスの活用

目次

データの「変換(射影)」

C#で配列やList<T>などのコレクションを扱う際、「すべての数値を2倍にしたい」「オブジェクトのリストから、特定のプロパティだけを抜き出したい」「計算結果を含む新しい形式のデータを作りたい」といった変換処理は頻繁に発生します。

LINQ(Language Integrated Query)のSelectメソッドは、コレクションの各要素に対して指定した変換関数を適用し、その結果を新しいシーケンスとして返すためのメソッドです。データベース用語では「射影(Projection)」とも呼ばれます。

この記事では、Selectメソッドの基本的な使い方から、匿名型を利用したデータ構造の変換、そしてインデックス(要素番号)を利用した処理について解説します。


Selectメソッドの基本:値の変換

Selectメソッドは、ラムダ式 x => ... を引数に取り、コレクションの各要素 x をどのように変換するかを定義します。入力と出力のデータ型は異なっていても構いません(例:intstring に変換するなど)。

コード例:数値の加工

整数の配列に対し、それぞれの値を2乗(自分自身を掛ける)した新しいシーケンスを生成する例です。

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

public class SelectBasicExample
{
    public static void Main()
    {
        // 元のデータ(整数配列)
        var numbers = new[] { 2, 4, 6, 8, 10 };

        // 各要素を 2乗 する変換処理
        // 入力(int) -> 出力(int)
        var squaredNumbers = numbers.Select(n => n * n);

        Console.WriteLine($"元の値: {string.Join(", ", numbers)}");
        Console.WriteLine($"変換後: {string.Join(", ", squaredNumbers)}");
        
        // 文字列への変換例
        // 入力(int) -> 出力(string)
        var stringNumbers = numbers.Select(n => $"No.{n}");
        Console.WriteLine($"文字列: {string.Join(", ", stringNumbers)}");
    }
}

出力結果:

元の値: 2, 4, 6, 8, 10
変換後: 4, 16, 36, 64, 100
文字列: No.2, No.4, No.6, No.8, No.10

応用:匿名型を利用した構造の変換

Selectメソッドが真価を発揮するのは、オブジェクトのリストから必要な情報だけを抽出・加工して、新しい「形」を作る場合です。

この際、わざわざ結果用のクラスを定義しなくても、「匿名型(Anonymous Type)」を使用することで、その場限りのデータ構造を定義して返すことができます。

コード例:計算結果を含む新しいオブジェクトの生成

商品データ(単価と数量)を持つクラスのリストから、商品名と「合計金額」を持つ新しいリストを生成します。

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

// 商品クラス
public class ProductItem
{
    public string Name { get; set; }
    public int UnitPrice { get; set; }
    public int Quantity { get; set; }
}

public class SelectProjectionExample
{
    public static void Main()
    {
        var cartItems = new List<ProductItem>
        {
            new ProductItem { Name = "Coffee Beans", UnitPrice = 1500, Quantity = 2 },
            new ProductItem { Name = "Filter Papers", UnitPrice = 500, Quantity = 1 },
            new ProductItem { Name = "Coffee Mill", UnitPrice = 3000, Quantity = 1 }
        };

        // Select を使って、必要な情報だけを持つ「匿名型」に変換(射影)する
        var receipts = cartItems.Select(item => new
        {
            item.Name, // プロパティ名を省略すると元の名前が使われる
            TotalPrice = item.UnitPrice * item.Quantity, // 計算結果に新しい名前を付ける
            IsExpensive = item.UnitPrice >= 2000 // 条件判定の結果も含められる
        });

        Console.WriteLine("--- 注文明細 ---");

        // 変換された匿名型のリストを処理
        foreach (var receipt in receipts)
        {
            string note = receipt.IsExpensive ? " [高級品]" : "";
            Console.WriteLine($"{receipt.Name}: {receipt.TotalPrice:C}{note}");
        }
    }
}

出力結果:

--- 注文明細 ---
Coffee Beans: ¥3,000
Filter Papers: ¥500
Coffee Mill: ¥3,000 [高級品]

このように、元のクラス(ProductItem)には存在しないTotalPriceIsExpensiveといったプロパティを、Selectの中で動的に生成できます。


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

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

構文: collection.Select((item, index) => ...)

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

コード例:ランキング形式の文字列生成

タイムを記録した配列から、順位(インデックス + 1)付きの文字列を生成する例です。

using System;
using System.Linq;

public class SelectIndexExample
{
    public static void Main()
    {
        // レースのタイム結果(速い順に並んでいると仮定)
        var lapTimes = new[] { 45.2, 46.8, 47.1, 48.5 };

        // 第2引数でインデックスを受け取る
        var ranking = lapTimes.Select((time, index) =>
        {
            int rank = index + 1; // 0始まりなので +1 する
            return $"{rank}位: {time:F1}秒";
        });

        Console.WriteLine(string.Join(Environment.NewLine, ranking));
    }
}

出力結果:

1位: 45.2秒
2位: 46.8秒
3位: 47.1秒
4位: 48.5秒

まとめ

LINQのSelectメソッドは、コレクションの各要素を新しい形に変換するための強力なツールです。

  • 値の変換: 計算や型変換を行います。
  • 構造の変換(射影): new { ... }(匿名型)と組み合わせることで、必要なプロパティだけを抽出したり、計算結果を含む新しいオブジェクトを作成したりできます。
  • インデックスの利用: (item, index) => ... の形式を使えば、要素の順番に基づいた処理も記述可能です。

Whereメソッド(フィルタリング)と並んで、LINQで最も頻繁に使用される重要なメソッドの一つです。

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

この記事を書いた人

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

目次