[C#] LINQの使い方まとめ

LINQの使い方をまとめました。

目次

必要な項目だけを取り出した新しいコレクション作る(Select)

LINQのSelectメソッドを使うと、配列・コレクションの各要素から必要な項目だけを取り出した新しいコレクションを作ることが出来ます。データの集まりから必要な項目だけを取り出すことを射影というらしいです。

Selectメソッドの実行結果は遅延評価になります。実際に結果が必要になった時に必要な項目を取り出す処理が実行されます。

Selectメソッドの使い方

Selectメソッドは引数に必要な項目を取り出すためのメソッドを指定します。各要素に対して指定したメソッドが実行されます。ラムダ式を使って匿名関数を渡すと簡単にSelectの引数を指定することができます。

この取り出すためのメソッドの引数はデータソースの要素の型になります。
このサンプルの場合、SampleDataクラスが引数になります。戻り値の型は自由です。
複数の値を返す場合は匿名クラスタプルを使うと便利です。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // SampleDataクラスのリストの宣言と初期化
        List<SampleData> list = new List<SampleData> { 
            new SampleData { Data1 = 1, Data2 = 2, Data3 = 3, Data4 = 4 },
            new SampleData { Data1 = 10, Data2 = 20, Data3 = 30, Data4 = 40 },
            new SampleData { Data1 = 100, Data2 = 200, Data3 = 300, Data4 = 400 },
        };
        // Selectメソッドで必要な項目だけを取り出す
        var select_list = list.Select(d => {
            // 匿名クラスを使い、必要な項目+要素を使った新しい項目(Sum)を返す
            return new { 
                Data1 = d.Data1,
                Data3 = d.Data3,
                Sum = d.Data1 + d.Data2 + d.Data3 + d.Data4
            };
        });
        // 結果の表示
        foreach (var data in select_list) {
            Console.WriteLine($"Data1={data.Data1}, Data3={data.Data3}, Sum={data.Sum}");
        }

        // 必要に応じて、リストや配列に変換
        var list2 = select_list.ToList(); // Listに変換
        var ary = select_list.ToArray();  // 配列に変換
    }
}

class SampleData 
{ 
    public int Data1 { get; set; }
    public int Data2 { get; set; }
    public int Data3 { get; set; }
    public int Data4 { get; set; }
}

実行結果はこんな感じです。

Data1=1, Data3=3, Sum=10
Data1=10, Data3=30, Sum=100
Data1=100, Data3=300, Sum=1000

Selectメソッドの戻り値はIEnumerable<T>型のコレクションになります。Tの部分はSelectメソッドに指定した項目を取り出すメソッドの戻り値の型になります。
サンプルコードの場合はIEnumerable<匿名クラス>です。
IEnumerableなのでforeachのinに指定することができます。

必要に応じて、ToListメソッドを使いListに変換したり、ToArrayメソッドを使い配列に変換することができます。

var list2 = select_list.ToList(); // Listに変換
var ary = select_list.ToArray();  // 配列に変換

要素のインデックスも同時に取り出す

Selectメソッドにはもうひとつ、要素のインデックスが取得できるオーバーロードがあります。
こちらもSelectメソッドの引数に必要な項目を取り出すメソッドを指定しますが、取り出すメソッドの引数は各要素のデータ型要素のインデックス(int型)になります。戻り値の型は自由です。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // SampleDataクラスのリストの宣言と初期化
        List<SampleData> list = new List<SampleData> { 
            new SampleData { Data1 = 1, Data2 = 2, Data3 = 3, Data4 = 4 },
            new SampleData { Data1 = 10, Data2 = 20, Data3 = 30, Data4 = 40 },
            new SampleData { Data1 = 100, Data2 = 200, Data3 = 300, Data4 = 400 },
        };
        // Selectメソッドで必要な項目だけを取り出す
        // ラムダ式の引数パラメータ d はSampleData型、i はint型(要素のインデックス)になる
        var select_list = list.Select((d, i) => {
            // 匿名クラスを使い、必要な項目+要素を使った新しい項目(Sum)を返す
            return new { 
                index = i,
                Data1 = d.Data1,
                Data3 = d.Data3,
                Sum = d.Data1 + d.Data2 + d.Data3 + d.Data4
            };
        });
        // 結果の表示
        foreach (var data in select_list) {
            Console.WriteLine($"Index={data.index}, Data1={data.Data1}, Data3={data.Data3}, Sum={data.Sum}");
        }
    }
}

class SampleData 
{ 
    public int Data1 { get; set; }
    public int Data2 { get; set; }
    public int Data3 { get; set; }
    public int Data4 { get; set; }
}
Index=0, Data1=1, Data3=3, Sum=10
Index=1, Data1=10, Data3=30, Sum=100
Index=2, Data1=100, Data3=300, Sum=1000

16行目 (d, i) => { i が要素のインデックスです。

条件にあった要素のみを抽出する(Where)

LINQのWhereメソッドを使うと、配列・コレクションなどから条件に一致した要素のみを抽出することができます。Whereメソッドは遅延評価になります。実際に結果が必要になった時にメソッドが実行されます。

Whereメソッドの使い方

Whereメソッドの引数には、抽出する条件を判定するメソッドを指定します。各要素に対して指定したメソッドが実行されます。ラムダ式を使って匿名関数を渡すと簡単にWhereに引数を指定することができます。

抽出する条件を判定するメソッドの引数はデータソースの要素のデータ型になります。サンプルの場合は引数はSampleDataクラス型です。
戻り値はBoolean型です。Trueが返ってきた要素が抽出されます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // SampleDataクラスのリストの宣言と初期化
        List<SampleData> list = new List<SampleData> { 
            new SampleData { Data1 = 1, Data2 = 2, },
            new SampleData { Data1 = 10, Data2 = 20, },
            new SampleData { Data1 = 100, Data2 = 200, },
        };
        // Whereメソッドで必要な要素だけを抽出する
        var where_list = list.Where(d => {
            // 各要素を判定して、True or False を返す
            return d.Data1 >= 10;
        });

        // 結果を表示
        Console.WriteLine($"抽出した件数={where_list.Count()}");
        foreach (var d in where_list) {
            Console.WriteLine($"Data1={d.Data1}, Data2={d.Data2}");
        }

        // 必要に応じて、配列・リストに変換
        var list2 = where_list.ToList(); // Listに変換
        var ary = where_list.ToArray();  // 配列に変換 
    }
}

class SampleData 
{ 
    public int Data1 { get; set; }
    public int Data2 { get; set; }
}

実行結果です。Data1が10以上の要素が抽出されました。

抽出した件数=2
Data1=10, Data2=20
Data1=100, Data2=200

Whereメソッドの戻り値はIEnumerable<T>型のコレクションになります。Tの部分はデータソースの要素のデータ型になります。サンプルの場合、TはSampleDataクラス型になります。

IEnumberable型なのでforeachinに指定することができます。(22行目)
また、必要に応じて、ToListメソッドを使いListに変換したり、ToArraryメソッドを使い配列に変換することができます。(27、28行目)

昇順・降順にならびかえる(Orderby・OrderByDescending

配列、コレクションのデータを昇順に並び替えるにはOrderByメソッドを、
降順に並び替えるにはOrderByDescendingメソッドを使います。

Orderby・OrderByDescendingメソッドの使いかた

OrderByメソッドOrderByDescendingメソッドそれぞれの引数にはデータの並び替えに使用するキーを返すメソッドを指定します。ここにはラムダ式を使い匿名関数を渡します。
引数で渡すキーを返すメソッドの引数配列、コレクションの要素のデータ型です。
戻り値並べ替えに使うキー(数値、文字列など)を返します。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // SampleDataクラスのリストの宣言と初期化
        List<SampleData> list = new List<SampleData> {
            new SampleData { Data1 = 11, Data2 = 20, },
            new SampleData { Data1 = 12, Data2 = 20, },
            new SampleData { Data1 = 10, Data2 = 22, },
            new SampleData { Data1 = 10, Data2 = 21, },
            new SampleData { Data1 = 10, Data2 = 20, },
        };

        // 昇順ソート
        var order_list1 = list.OrderBy(d => d.Data1);
        Console.WriteLine("OrderByを使って昇順ソート(キーはData1)");
        foreach (var data in order_list1) Console.WriteLine($"data1={data.Data1}, data2={data.Data2}");

        // 降順ソート
        var order_list2 = list.OrderByDescending(d => d.Data1);
        Console.WriteLine("OrderByDescendingを使って降順ソート(キーはData1)");
        foreach (var data in order_list2) Console.WriteLine($"data1={data.Data1}, data2={data.Data2}");
    }
}

class SampleData
{
    public int Data1 { get; set; }
    public int Data2 { get; set; }
}

出力結果です。

OrderByを使って昇順ソート(キーはData1)
data1=10, data2=22
data1=10, data2=21
data1=10, data2=20
data1=11, data2=20
data1=12, data2=20
OrderByDescendingを使って降順ソート(キーはData1)
data1=12, data2=20
data1=11, data2=20
data1=10, data2=22
data1=10, data2=21
data1=10, data2=20

複数キーで並び替える(OrderBy + ThenBy)

複数のキーを使って並べ替えをするには、OrderByメソッド、OrderByDescendingメソッドの後ろにThenByメソッドThenByDescendingメソッドをつなげて書きます。

昇順で並べる場合はThenByメソッド降順で並べる場合はThenByDescendingメソッドを使います。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // SampleDataクラスのリストの宣言と初期化
        List<SampleData> list = new List<SampleData> {
            new SampleData { Data1 = 11, Data2 = 20, },
            new SampleData { Data1 = 12, Data2 = 20, },
            new SampleData { Data1 = 10, Data2 = 22, },
            new SampleData { Data1 = 10, Data2 = 21, },
            new SampleData { Data1 = 10, Data2 = 20, },
        };

        // 複数キーでの並べ替え(Data1昇順、Data2昇順)
        var order_list3 = list.OrderBy(d => d.Data1).ThenBy(d => d.Data2);
        Console.WriteLine("OrderByでData1を昇順に並べた後でThenByでData2の昇順に並べる");
        foreach (var data in order_list3) Console.WriteLine($"data1={data.Data1}, data2={data.Data2}");

        // 複数キーでの並べ替え(Data1昇順、Data2降順)
        var order_list4 = list.OrderBy(d => d.Data1).ThenByDescending(d => d.Data2);
        Console.WriteLine("OrderByでData1を昇順に並べた後でThenByDescendingでData2の降順に並べる");
        foreach (var data in order_list4) Console.WriteLine($"data1={data.Data1}, data2={data.Data2}");
    }
}

class SampleData
{
    public int Data1 { get; set; }
    public int Data2 { get; set; }
}

処理結果です。

OrderByでData1を昇順に並べた後でThenByでData2の昇順に並べる
data1=10, data2=20
data1=10, data2=21
data1=10, data2=22
data1=11, data2=20
data1=12, data2=20
OrderByでData1を昇順に並べた後でThenByDescendingでData2の降順に並べる
data1=10, data2=22
data1=10, data2=21
data1=10, data2=20
data1=11, data2=20
data1=12, data2=20

並び順を反転する(Reverse)

Reverseメソッドを使って要素のならび順番を反転させることができます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // 配列要素の並び順を反転
        int[] ary = new int[] { 1, 2, 3, 4, 5, };
        Console.WriteLine($"逆の配列:[ {string.Join(" ", ary.Reverse())} ]");
        Console.WriteLine($"元の配列:[ {string.Join(" ", ary)} ]");

        // リスト要素の並び順を反転
        List<int> list = new List<int> { 1, 2, 3, 4, 5 };
        Console.WriteLine($"Reverse前のリスト:[ {string.Join(" ", list)} ]");
        list.Reverse();
        Console.WriteLine($"Reverse後のリスト:[ {string.Join(" ", list)} ]");
    }
}
逆の配列:[ 5 4 3 2 1 ]
元の配列:[ 1 2 3 4 5 ]
Reverse前のリスト:[ 1 2 3 4 5 ]
Reverse後のリスト:[ 5 4 3 2 1 ]

要素をN個ずつにまとめる(Chunk)

Chunkメソッドを使うと配列やリストの要素をn個ずつまとめることができます。

Chunkメソッドの使い方

Chunkメソッドの引数には何個毎にまとめるかを指定します。戻り値は指定された個数にまとめられたコレクションをもつコレクションです。
また最後に余った要素は指定された個数より少ない数でまとめられます。
サンプルでは10個の要素を3個ずつにまとめています。最後の要素(チャンク)だけ要素数1になる。

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

namespace TestProject;
class Program 
{
    static void Main(string[] args)
    {
        //データソース
        List<int> list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        //listを3つずつに分割する
        foreach (var chunk in list.Chunk(3)) {
            Console.WriteLine("chank data-----");
            foreach (var element in chunk) {
                Console.WriteLine(element);
            }
        }
    }
}

実行結果です

chank data-----
1
2
3
chank data-----
4
5
6
chank data-----
7
8
9
chank data-----
10

範囲を指定して要素を取得する(Take・Skip)

範囲を指定してリストなどの順番に並んだデータから要素を取得するにはTakeメソッド、Skipメソッドを組み合わせて使います。
また、C#10からTakeメソッドにRangeクラスが指定できるようになったのでそれを使っての範囲指定することもできます。

Take、Skipメソッドの使い方

Takeメソッドは先頭から引数で指定された数だけ要素を取り出します。
Skipメソッドは先頭から引数で指定された数だけ飛ばしその後ろから要素を取り出します。
この2つのメソッドを組み合わせて、範囲を指定して要素を取り出すことが出来ます。
Skipメソッドで開始地点を指定してTakeメソッドでそこから何個要素を取り出すかを指定します。
こんなイメージです、

LINQ Take、Skipメソッドの使い方

Takeメソッドの引数に対象の要素より大きい数を指定した場合は残りすべて要素が返ってきます。Skipメソッドの場合は空のリストが返ってきます。

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

namespace LinqTest;
class Program
{
    static void Main() {
        //取得対象のリスト
        var list = new List<int> { 0, 1, 2, 3, 4, 5 };

        //インデックス1、2,3を取得
        foreach (var item in list.Skip(1).Take(3)) { 
            Console.WriteLine(item);
        }
    }
}
1
2
3

TakeメソッドにRangeを渡して範囲指定する

C#10からTakeメソッドのオーバーロードが追加され引数にRangeを指定できるようになりました。
Rangeは「start..end」という構文で指定することができます。startとendの部分にインデックスを指定するのですが、endのインデックスは含まない範囲になるので注意してください。
上記サンプルと同じようにインデックス1,2,3の範囲を指定したい場合「1..4」となります。
また「^1」のようにすると末尾から1番目という意味になります。

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

namespace LinqTest;
class Program
{
    static void Main() {
        //取得対象のリスト
        var list = new List<int> { 0, 1, 2, 3, 4, 5 };

        //インデックス1、2,3を取得
        Console.WriteLine($"1..4  : {string.Join(",", list.Take(1..4))}");
        Console.WriteLine($"1..^2 : {string.Join(",", list.Take(1..^2))}");
    }
}
1..4  : 1,2,3
1..^2 : 1,2,3

条件を満たす最初の要素を取得する(First、FirstOrDefault)

FirstメソッドFirstOrDefalutメソッドを使うと、配列・コレクションから条件を満たす最初を要素を取り出すことができます。2つのメソッドの違いは、
Firstメソッドは条件を満たす要素がなかった場合にエラーになり、
FirstOrDefaltメソッドは条件を満たす要素がなかった場合に要素のデータ型のデフォルト値が返されます。

また、条件を指定せず最初の要素を取得することもできます。

条件を満たす最初の要素を取り出す

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

class Program
{
    public static void Main()
    {
        // データソース(SampleDataクラス型のリスト)
        var list = new List<SampleData> {
            new SampleData { Data1 = 10, Data2 = 11 },
            new SampleData { Data1 = 10, Data2 = 12 },
            new SampleData { Data1 = 20, Data2 = 11 },
            new SampleData { Data1 = 20, Data2 = 12 },
        };
        // FirstOrDefaultメソッドで条件を満たす最初の要素を取得
        SampleData first_data = list.FirstOrDefault(d => d.Data1 == 20);
        Console.WriteLine($"条件(Data1が20)を満たす最初の要素=[ Data1={first_data.Data1}, Data2={first_data.Data2} ]");

        // 条件を満たす要素がない場合はデフォルト値(null)が返ってくる
        first_data = list.FirstOrDefault(d => d.Data1 == 100);
        Console.WriteLine($"first_dataはnullですか?={first_data is null}");
    }
}

class SampleData
{
    public int Data1 { get; set; }
    public int Data2 { get; set; }
}
条件(Data1が20)を満たす最初の要素=[ Data1=20, Data2=11 ]
first_dataはnullですか?=True

条件に関係なく最初の要素を取得

First、FirstOrDefaultメソッドにはオーバーライドがあり、引数に何も指定しなかった場合に先頭の要素を取得することができます。
Firstメソッドは要素数が0個の場合にエラーになるので注意してください。
FirstOrDefaultメソッドはデフォルト値が返ってきます。

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

class Program
{
    public static void Main()
    {
        // 先頭の要素を取得
        List<int> list = new List<int> { 1, 2, 3 };
        Console.WriteLine($"listの先頭の要素={list.First()}");
        Console.WriteLine($"listの先頭の要素={list.FirstOrDefault()}");

        // 空のリストの場合
        List<int> empty_list = new List<int>();
        //Console.WriteLine($"empty_listの先頭の要素={empty_list.First()}"); // エラーになる
        Console.WriteLine($"empty_listの先頭の要素={empty_list.FirstOrDefault()}");
    }
}
listの先頭の要素=1
listの先頭の要素=1
empty_listの先頭の要素=0

各要素の合計(Sum)、最小値(Min)、最大値(Max)を求める

・各要素合計を取得するにはSumメソッド
・各要素の中から最小値を取得するにはMinメソッド
・最大値を取得するにはMaxメソッド
を使います。

要素が数値だけ(int[]List<double>など)の場合は各メソッドに引数はありません。
各要素に複数の項目がある場合は各メソッドの引数に集計に使う項目を返すメソッドを指定します。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // 配列の各要素の合計、最小値、最大値
        int[] ary = new int[] { 2, 4, 1, 6, 8, 7 };
        Console.WriteLine($"aryの合計 ={ary.Sum()}");
        Console.WriteLine($"aryの最小値={ary.Min()}");
        Console.WriteLine($"aryの最大値={ary.Max()}");

        // Listの各要素の合計、最小値、最大値
        List<int> list = new List<int> { 2, 4, 1, 6, 8, 7 };
        Console.WriteLine($"listの合計 ={list.Sum()}");
        Console.WriteLine($"listの最小値={list.Min()}");
        Console.WriteLine($"listの最大値={list.Max()}");

        // Dictionaryの各要素の合計、最小値、最大値
        // Sum、Min、Maxの各引数に集計する項目を返すメソッドを指定する
        Dictionary<string, int> dic = new Dictionary<string, int> {
            { "a", 90 },
            { "b", 20 },
            { "c", 30 },
            { "d", 10 },
        };
        Console.WriteLine($"dicの合計 ={dic.Sum(kv => kv.Value)}");
        Console.WriteLine($"dicの最小値={dic.Min(kv => kv.Value)}");
        Console.WriteLine($"dicの最大値={dic.Max(kv => kv.Value)}");
    }
}

実行結果です。

aryの合計 =28
aryの最小値=1
aryの最大値=8
listの合計 =28
listの最小値=1
listの最大値=8
dicの合計 =150
dicの最小値=10
dicの最大値=90

また、MinとMaxは日付型(DateTime)のコレクションにも使えます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        List<DateTime> list = new List<DateTime> { 
            new DateTime(2024, 6, 15),
            new DateTime(2025, 6, 10),
            new DateTime(2024, 6, 12),
        };

        Console.WriteLine($"Min = {list.Min()}");
        Console.WriteLine($"Max = {list.Max()}");
    }
}
Min = 2024/06/12 0:00:00
Max = 2025/06/10 0:00:00

最大・最小の項目をもった要素を取得する(MaxBy・MinBy)

MaxByメソッド、MinByメソッドを使うと最大・最小の項目を持った要素を取得することができます。

最大の項目を探すにはMaxByメソッド最小の項目を探すにはMinByメソッドを使います。
それぞれの第1引数に対象の項目を返すメソッドを指定します。
戻り値はそれぞれ最初に見つかった最大、最小の項目を持つ要素になります。

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

namespace TestProject;
class Program
{
    static void Main() {

        var list1 = new List<(int ID, string Name)> { 
            (1, "YasNote"), (2, "Name1"), (1, "Name5"), (3, "Name2"), (4, "Name3"), (4, "Name4")
        };
        //最大の項目を持つ要素を取得
        var max_element = list1.MaxBy(x => x.ID);
        Console.WriteLine($"最大:{max_element}");

        //最小の項目持つ要素を取得
        var min_element = list1.MinBy(x => x.ID);
        Console.WriteLine($"最小:{min_element}");
    }
}
最大:(4, Name3)
最小:(1, YasNote)

すべての要素が条件を満たすか判定する(All)

Allメソッドを使うと、配列・コレクションのすべての要素が条件を満たすかどうか判定することが出来ます。

Allメソッドの引数には条件を判定するメソッドを指定します。この指定したメソッドがすべての要素に対して実行されます。ラムダ式を使って匿名関数を渡すと簡単にAllメソッドに引数を指定することができます。
Allメソッドの戻り値は、すべての要素が条件を満たす場合にTrue、条件を満たさない場合にFalseが返されます。

条件を判定するメソッドの引数にはデータソース(配列、リストなど)の各要素が渡されます。
条件を判定するメソッドの戻り値はBoolean型(TrueまたはFlase)です。
渡された要素が条件を満たす場合にTrue、満たさない場合にFalseを返すようにします。

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

class Program
{
    public static void Main()
    {
        // データソース(int型の配列)
        var ary = new int[] { 1, 2, 3, 4, 5 };
        // Allメソッドを使ってすべての要素が条件を満たすか判定する
        var all_result = ary.All(i => i == 3);
        Console.WriteLine($"aryの全ての要素が3かどうか?={all_result}");

        all_result = ary.All(i => i < 10);
        Console.WriteLine($"aryの全ての要素が10以下かどうか?={all_result}");


        // データソース(SampleDataクラスのリスト)
        var list = new List<SampleData> {
            new SampleData { Data1 = 10, Data2 = 11 },
            new SampleData { Data1 = 10, Data2 = 12 },
            new SampleData { Data1 = 10, Data2 = 13 },
        };
        // Allメソッドを使ってすべての要素が条件を満たすか判定する
        all_result = list.All(d => d.Data1 == 10);
        Console.WriteLine($"listの全ての要素(Data1)が10かどうか?={all_result}");
    }
}

class SampleData
{
    public int Data1 { get; set; }
    public int Data2 { get; set; }
}

実行結果です。

aryの全ての要素が3かどうか?=False
aryの全ての要素が10以下かどうか?=True
listの全ての要素(Data1)が10かどうか?=True

条件を満たす要素が含まれているか判定する(Any)

Anyメソッドを使うと、配列・コレクションのデータ内に条件を満たす要素があるかどうか判定することができます。

Anyメソッドの引数には条件を判定するメソッドを指定します。戻り値は、条件を満たす要素が1つ以上含まれている場合True、満たさない場合Falseが返ってきます。

条件を判定するメソッドの引数にはデータソース(配列、リストなど)の各要素が渡されます。int型の配列ならint型、クラスのリストならクラスが渡されます。
条件を判定するメソッドの戻り値は、Boolean型(渡された要素が条件を見たす場合にTrue、満たさない場合にFalse)の値を返すようにします。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        var list = new List<int> { 1, 2, 3, 4, 5, 4, 3, 2, 1 };

        bool any_result = list.Any(i => i == 3);
        Console.WriteLine($"要素に3があるか? = {any_result}");

        any_result = list.Any(i => i == 10);
        Console.WriteLine($"要素に10があるか? = {any_result}");
    }
}
要素に3があるか? = True
要素に10があるか? = False

要素の個数を取得する(Count)

要素の個数を取得するには、Countメソッドを使います。戻り値はint型の要素数になります。
また、要素の数が多い場合はLongCountメソッドでLong型で要素の個数を取得することができます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // 配列の要素数
        int[] ary = new int[] { 2, 4, 1, 6, 8, 7 };
        Console.WriteLine($"aryの要素数(int) ={ary.Count()}");
        Console.WriteLine($"aryの要素数(long)={ary.LongCount()}");

        // Listの要素数
        List<int> list = new List<int> { 2, 4, 1, 6, 8, 7 };
        Console.WriteLine($"listの要素数(int) ={list.Count()}");
        Console.WriteLine($"listの要素数(long)={list.LongCount()}");

        // Dictionaryの要素数
        Dictionary<string, int> dic = new Dictionary<string, int> {
            { "a", 90 },
            { "b", 20 },
            { "c", 30 },
            { "d", 10 },
        };
        Console.WriteLine($"dicの要素数(int) ={dic.Count()}");
        Console.WriteLine($"dicの要素数(long)={dic.LongCount()}");

        //空(要素0個)のリスト
        List<int> listEmpty = new List<int> { };
        //要素が0個場合、AnyメソッドはFalseを返す
        if (!listEmpty.Any()) {
            Console.WriteLine("listEmptyは空です。");
        }
    }
}

出力結果です。

aryの要素数(int) =6
aryの要素数(long)=6
listの要素数(int) =6
listの要素数(long)=6
dicの要素数(int) =4
dicの要素数(long)=4
listEmptyは空です。

2つのコレクションを結合する(Zip)

Zipメソッドを使うと複数のコレクション(リストなど)を結合(マージ)して1つのコレクションにすることができます。

2つのリストを結合する

1つ目のリストのZipメソッドに引数に2つ目のリストを指定します。
要素の数が異なる場合、少ないほうに合わせてマージされます。
戻り値はそれぞれの要素が入ったタプル(First、Secondという名前付き)が返ってきます。

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

namespace zip_test {
    class Program {
        static void Main(string[] args)
        {
            var list1 = new List<int> { 1, 2, 3, 4, 5 };
            var list2 = new List<string> { "a", "b", "c", "d" }; //こっちの要素の少ない方に合わせてマージされる

            //2つのリストを結合する
            foreach (var ret in list1.Zip(list2)) {
                Console.WriteLine($"{ret.First}:{ret.Second}");
            }

            //2つのリストを結合する(結果のタプルを分解して受け取る)
            foreach ((var l1, var l2) in list1.Zip(list2)) {
                Console.WriteLine($"{l1}:{l2}");
            }
        }
    }
}

このように要素の少ない方に合わせてマージされる。

1:a
2:b
3:c
4:d

3つのリストを結合する

C#10からZipメソッドのオーバーロードが追加され3つめのリストが指定できるようになりました。
戻り値はFirst、Second、Thirdという名前付きタプルが返ってきます。
こちらも要素の少ないリストに合わせてマージされます。

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

namespace zip_test;
class Program
{
    static void Main() {
        var list1 = new List<int> { 1, 2, 3, 4, 5 };
        var list2 = new List<string> { "a", "b", "c", "d" };
        var list3 = new List<string> { "あ", "い", "う" };

        //C#10から3つのコレクションを結合できる
        var zipList = list1.Zip(list2, list3);
        foreach ((var l1, var l2, var l3) in zipList) {
            Console.WriteLine($"{l1}:{l2}:{l3}");
        }
    }
}
1:a:あ
2:b:い
3:c:う

2つのコレクションを内部結合する(Join)

Joinメソッドを使うと指定した項目が同じ2つのコレクションを結合して新しいコレクションにすることができます。
Joinメソッドはちょっと複雑で引数が4つあります。
1つ目に結合するコレクション、2つ目に結合されるコレクションのキー項目を返すメソッド、3つ目に結合するコレクションのキー項目を返すメソッド、4つ目に結合された新しいコレクションの項目を返すメソッドを指定します。

サンプルコードでは2つのリストのidが同じ要素をくっつけています。

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

class Program
{
    static void Main()
    {
        var nameList = new List<(int id, string name)> { 
            (1, "name1"),
            (2, "name2"),
            (3, "name3"),
            (4, "name4"),
            (5, "name5"),
        };
        var ageList = new List<(int id, int age)> { 
            (0, 100),
            (1, 10),
            (2, 20),
            (3, 33),
        };

        //Joinメソッドでキー項目(id)の一致する要素を結合
        var newList = nameList.Join(
            ageList,    //結合するリスト
            n => n.id,  //結合されるリストのキー
            a => a.id,  //結合するリストのキー
            (name, age) => (ID: name.id, Name: name.name, Age: age.age) //結合されたリスト達から新しい項目を返すところ
        );
        foreach (var n in newList)
        {
            Console.WriteLine(n);
        }
    }
}

2つのリストを結合してあたらしい項目を持ったタプルを返しています。

(1, name1, 10)
(2, name2, 20)
(3, name3, 33)

リストの中のリストを1つにまとめる(SelectMany)

SelectManyメソッドを使うと、リストの中にあるリストを1つにまとめることができます。
SelectManyメソッドの引数にはまとめたいリストや配列を返すメソッドを指定します。
「まとめたいリストや配列を返すメソッド」の引数にはリストの各要素が渡されます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // SampleDataクラスのリストの宣言と初期化
        List<SampleData> list = new List<SampleData> {
            new SampleData { Name = "a", DataList = new List<int> { 1, 2, 3 } },
            new SampleData { Name = "b", DataList = new List<int> { 4, 5, 6 } },
            new SampleData { Name = "c", DataList = new List<int> { 7, 8, 9 } },
        };

        // 元のリスト
        Console.WriteLine("元のリスト");
        foreach (var data in list) Console.WriteLine($"Name={data.Name}, DataList=[{string.Join(", ", data.DataList)}]");

        // SelectManyでリストの中のリストを1つにまとめる
        IEnumerable<int> result1 = list.SelectMany(data => data.DataList);
        Console.WriteLine("\nSelectManyでリストの中のリストを1つにまとめる");
        Console.WriteLine($"{string.Join(", ", result1)}");
    }
}

class SampleData
{
    public string Name { get; set; }
    public List<int> DataList { get; set; }
}

SelectManyメソッドを使ってまとめているのは、サンプルコード20行目です。
引数にはまとめたいリスト(SampleDataクラスのDataList)を返すメソッドを指定しています。
出力結果このようになります。

元のリスト
Name=a, DataList=[1, 2, 3]
Name=b, DataList=[4, 5, 6]
Name=c, DataList=[7, 8, 9]

SelectManyでリストの中のリストを1つにまとめる
1, 2, 3, 4, 5, 6, 7, 8, 9

まとめたものと他の項目と組み合わせる

リストの中のリストを1つにまとめるときに他の項目と組み合わせることが出来ます。
SelectManyメソッドの第1引数にまとめたいリストや配列を返すメソッド
第2引数に外側のリストの各要素とまとめた値1つ1つを使って新しい型を返すメソッドを指定します。

自分でもなにを言ってるかさっぱりなのでサンプルコードをどうぞ。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // SampleDataクラスのリストの宣言と初期化
        List<SampleData> list = new List<SampleData> {
            new SampleData { Name = "a", DataList = new List<int> { 1, 2, 3 } },
            new SampleData { Name = "b", DataList = new List<int> { 4, 5, 6 } },
            new SampleData { Name = "c", DataList = new List<int> { 7, 8, 9 } },
        };

        // SelectManyでリストの中のリストを1つにまとめたものを他の項目と組み合わせる
        var result = list.SelectMany(
            data => data.DataList,
            (data, DataList_value) => new { Name = data.Name, Value = DataList_value }
        );
        // 結果を表示
        foreach (var d in result)
        {
            Console.WriteLine($"Name={d.Name}, Value={d.Value}");
        }
    }
}

class SampleData
{
    public string Name { get; set; }
    public List<int> DataList { get; set; }
}

こんな感じにまとめることが出来ます。

Name=a, Value=1
Name=a, Value=2
Name=a, Value=3
Name=b, Value=4
Name=b, Value=5
Name=b, Value=6
Name=c, Value=7
Name=c, Value=8
Name=c, Value=9

最後に

ここまできてなんですが、
LINQってなに?という方は、こちらの記事を見てください。

参考資料

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