【C#】LINQメソッドの使い方まとめ

LINQメソッドの使い方を用途ごとに簡単にまとめます。
LINQにどのようなメソッドが用意されているのかを把握しておくことで、コードを簡潔に書くことができます。
※本稿での「シーケンス」は「IEnumerable<T>」を指しています。

【検証環境】.NET Framework 4.7.2

要素の判定

Any

Any メソッドはシーケンスに要素が含まれているかを判定します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);

//要素が存在するか
bool any = nums.Any();  // ⇒ true

//条件と一致する要素が存在するか 
bool any_Condition = nums.Any(n => n == 1);   // ⇒ true

All

All メソッドはシーケンスのすべての要素が条件に一致するかを判定します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);

//指定した要素が存在するか
bool all = nums.All(n => n > 1);   // ⇒ true

注意点として、シーケンスが空の場合はtrueを返します。All メソッドを使う場合はAny メソッドと組み合わせて使うことを推奨します。

//空のシーケンスを生成
IEnumerable<int> empty = Enumerable.Empty<int>();

//シーケンスが空だと無条件でtrueを返す
bool all = empty.All(n => n > 1); // ⇒ true

Contains

Contains メソッドはシーケンスに指定した要素が含まれるかを判定します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);

//指定した要素が存在するか
bool contains = nums.Contains(0);   // ⇒ false

SequenceEqual

SequenceEqualメソッド2つのシーケンスが等しいかを判定します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);

//比較用リスト生成
List<int> nums1 = new List<int>() { 9, 8, 7, 6, 5, 4, 3, 2, 1, };
List<int> nums2 = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, };

//2つのコレクションが等しいか
bool sequenceEqual1 = nums.SequenceEqual(nums1);   // ⇒ false ※比較には順番も含まれる
bool sequenceEqual2 = nums.SequenceEqual(nums2);   // ⇒ true
bool sequenceEqual3 = nums.SequenceEqual(nums1.OrderBy(n => n));   // ⇒ true ※整列して順序も合わせればtrue

単一要素の取得

First / FirstOrDefault

First / FirstOrDefault メソッドはシーケンスの最初の要素を返します。

それぞれの違いとして、シーケンスに要素が含まれていない場合に、First は例外エラーになりますが、FirstOrDefault は規定値(stringはnull、intは0…)を返します。Firstはシーケンスに要素が確実に存在する場合に使用します

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int first = nums.First();   // ⇒ 1
int firstOrDefault = nums.FirstOrDefault();   // ⇒ 1

//空のシーケンス生成
IEnumerable<int> empty = Enumerable.Empty<int>();
int firstEmp = empty.First();   // ⇒ <span class="red">例外エラー</span>
int firstOrDefaultEmp = empty.FirstOrDefault(); // ⇒ 0(規定値)

//条件指定も可能
int first_Condition  = nums.First(n => n == 10);
int firstOrDefault_Condition = nums.FirstOrDefault(n => n == 10);

Last / LastOrDefault

Last /LastOrDefault メソッドはシーケンスの最後の要素を返します。

First / FirstOrDefaultと同様に、シーケンスに要素が含まれていない場合に、Lastは例外エラーになりますが、LastOrDefault は規定値(stringはnull、intは0…)を返します。Lastはシーケンスに要素が確実に存在する場合に使用します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int last = nums.last();   // ⇒ 9
int lastOrDefault = nums.lastOrDefault();   // ⇒ 9

//空のシーケンス生成
IEnumerable<int> empty = Enumerable.Empty<int>();
int lastEmp = empty.last();   // ⇒ 例外エラー
int lastOrDefaultEmp = empty.lastOrDefault(); // ⇒ 0(規定値)

//条件指定も可能
int last_Condition  = nums.last(n => n == 10);
int lastOrDefault_Condition = nums.lastOrDefault(n => n == 10);

Single / SingleOrDefault

Single/ SingleOrDefault メソッドはシーケンスの唯一の要素を返します。

First / FirstOrDefaultと同様に、シーケンスに要素が含まれていない場合に、Singleは例外エラーになりますが、SingleOrDefault は規定値(stringはnull、intは0…)を返します。Singleはシーケンスに要素が確実に1つだけ存在する場合に使用します

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int last = nums.last();   // ⇒ 9
int lastOrDefault = nums.lastOrDefault();   // ⇒ 9

//空のシーケンス生成
IEnumerable<int> empty = Enumerable.Empty<int>();
int lastEmp = empty.last();   // ⇒ 例外エラー
int lastOrDefaultEmp = empty.lastOrDefault(); // ⇒ 0(規定値)

//条件指定も可能
int last_Condition  = nums.last(n => n == 10);
int lastOrDefault_Condition = nums.lastOrDefault(n => n == 10);

First と Singleはどちらもシーケンスから1つの要素を取得しますが、Singleは条件に一致する要素が複数存在すると例外エラーが発生します。Firstは複数あっても最初に見つかった要素を返します。
Singleはシーケンスの中に該当する要素が確実に1つの場合に使用します。

ElementAt / ElementAtOrDefault

ElementAt / ElementAtOrDefault メソッド指定したインデックス位置の要素を返します。

First / FirstOrDefaultと同様に、シーケンスに要素が含まれていない場合に、ElementAtは例外エラーになりますが、ElementAtOrDefault は規定値(stringはnull、intは0…)を返します。ElementAtはシーケンスに要素が確実に存在する場合に使用します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int elementAt = nums.ElementAt(5);   // ⇒ 6
int elementAtOrDefault = nums.ElementAtOrDefault(5);   // ⇒ 6

//空のシーケンス生成
IEnumerable<int> empty = Enumerable.Empty<int>();
int lelementAtEmp = empty.ElementAt(5);   // ⇒ 例外エラー
int elementAtOrDefaultEmp = empty.ElementAtOrDefault(5); // ⇒ 0(規定値)

複数要素の取得

Select

Select メソッド指定した要素を返します。(射影)
ラムダ式の第2引数を指定すると、要素のインデックスを返すことができます。

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public static IEnumerable<Person> GetPerson() 
    {
        return new List<Person>()
        {
            new Person()
            {
                Name = "ペン太",
                Age = 25
            },
            new Person()
            {
                Name = "ペン子",
                Age = 30,
            },
            new Person()
            {
                Name = "ホゲ助",
                Age = 50,
            }
        };
    }
}

static void Main(string[] args)
{
    IEnumerable<Person> people = Person.GetPerson();
    //Nameのシーケンスを取得
    IEnumerable<string> select = person.Select(p => p.Name);
    //匿名型でシーケンスを取得
    var anonymous = person.Select(p => new { a = p.Name, b = p.Age, c = p.Height });

    //要素とインデックスを取得
    var select2 = person.Select((p, index) => (p.Name, index));
}

Where

Where メソッド指定した条件と一致するシーケンスを返します。(フィルター処理)

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int elementAt = nums.ElementAt(5);   // ⇒ 6
IEnumerable<int> where    = nums.Where(n => n > 5);    // ⇒ 6, 7, 8, 9

Distinct

Distinct メソッド一意の要素を返します。(重複を取り除く)

List<int> nums = new List<int>() { 1, 2, 2, 3, 3, 3,};

IEnumerable<int> distinct = nums.Distinct();    // ⇒ 1, 2, 3

Skip / SkipWhile

Skip / SkipWhileメソッドは任意の要素をスキップした残りの要素を返します。

Skipは引数にスキップする要素数を、SkipWhileは引数にスキップする条件を渡します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
//指定した数の要素をスキップして、残りの要素を返す
IEnumerable<int> skip = nums.Skip(5);   // ⇒ 6, 7, 8, 9
//指定した条件と一致するまでスキップして、残りの要素を返す
IEnumerable<int> skipWhile = nums.SkipWhile(n => n < 5);    // ⇒ 5, 6, 7, 8, 9

Take / TakeWhile

Take / TakeWhileメソッド先頭から任意の要素を返します。

Takeは引数に先頭から取得する要素数を、TakeWhileは引数に先頭から取得する条件を渡します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
//先頭から指定した数の要素を返す
IEnumerable<int> take = nums.Take(5);   // ⇒ 1, 2, 3 4, 5 
//先頭から指定した条件と一致するまでの要素を返す
 IEnumerable<int> takeWhile = nums.TakeWhile(n => n < 5);    // ⇒ 1, 2, 3, 4

コレクションの生成

ToArray

ToArray メソッドはシーケンスから配列を生成します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int[] toArray = nums.ToArray();

ToList

ToList メソッドList<T>を生成します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
List<int> toList = nums.ToList();

ToDictionary

ToDictionary メソッドはシーケンスからDictionary<TKey, TValue>を生成します。

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public static IEnumerable<Person> GetPerson() 
    {
        return new List<Person>()
        {
            new Person()
            {
                Name = "ペン太",
                Age = 25
            },
            new Person()
            {
                Name = "ペン子",
                Age = 30,
            },
            new Person()
            {
                Name = "ホゲ助",
                Age = 50,
            }
        };
    }
}

static void Main(string[] args)
{
    IEnumerable<Person> people = Person.GetPerson();
    //NameをKeyに, 要素をValueにする場合 ※Valueを省略すると要素になる
    Dictionary<string, Person> toDic = person.ToDictionary(key => key.Name);
    //NameをKeyに、AgeをValueにする場合
    Dictionary<string, int> toDictionary = person.ToDictionary(key => key.Name, value => value.Age);
}

ToLookup

ToLookup メソッドはシーケンスからILookup<TKey, TElement>を生成します。

ILookup型はDictionary型と同様に、キーを指定してアクセス可能です。違いとしてはDictionaryがキーを単一の値に割り振るのに対して、ILookupはキーを複数の要素に対して割り振ります。つまりグループ化をしているということです。

public static IEnumerable<Person> GetPerson() 
{
    return new List<Person>()
    {
        new Person()
        {
            Name = "ペン太",
            Age = 25
        },
        new Person()
        {
            Name = "ペン太",
            Age = 30,
        },
        new Person()
        {
            Name = "ホゲ助",
            Age = 50,
        }
    };
}

static void Main(string[] args)
{
    IEnumerable<Person> people = Person.GetPerson();
    //Nameをキーにしてグループ化
    ILookup<string, Person> toLookup = person.ToLookup(p => p.Name);

    //キーが"ペン太"のシーケンスを取得
    IEnumerable<Person> penta = toLookup["ペン太"];    // ⇒ Count = 2
}   

Concat

Concat メソッドは2つのシーケンスどうしを連結したシーケンスを返します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
IEnumerable<int> concat = nums.Concat(Enumerable.Range(10, 5)); // 1,2,3,4,5,6,7,8,10,11,12,13,14

AddRangeとの違いについて
AddRangeはList型のメソッドで、ConcatはIEnumerable型の拡張メソッドです。
AddRangeは戻り値がvoidで対象のコレクションに追加しますが、Concatは戻り値に連結した新しいシーケンスを生成して返します。

統計

Count

Count メソッドはシーケンスの要素数を返します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int count = nums.Count(); // ⇒ 9

Average

Average メソッドはシーケンスの平均値を返します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
double average = nums.Average();   // ⇒ 5

Sum

Sum メソッドはシーケンスの合計値を返します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int sum = nums.Sum();   // ⇒ 45

Max / Min

Max メソッドはシーケンスの最大値を返します。
Min メソッドはシーケンスの最小値を返します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
int max = nums.Max();   // ⇒ 9
int min = nums.Min();   // ⇒ 1

並び替え

OrderBy / OrderByDescending

OrderByメソッドはシーケンスを昇順に並び替えて返します。
OrderByDescendingメソッドはシーケンスを降順に並び替えて返します。

※並び替え元のシーケンスの順序は変わりません。

public static IEnumerable<Person> GetPerson() 
{
    return new List<Person>()
    {
        new Person()
        {
            Name = "ペン太",
            Age = 30
        },
        new Person()
        {
            Name = "ペン子",
            Age = 25,
        },
        new Person()
        {
            Name = "ホゲ助",
            Age = 50,
        }
    };
}

static void Main(string[] args)
{
    //※personの順序は変わらない

    //昇順
    var orderBy = person.OrderBy(p => p.Age);
    //降順
    var orderByDescending = person.OrderByDescending(p => p.Age);
}  

ThenBy / ThenByDescending

ThenByメソッドはOrderByのソート結果をさらに別のキーで昇順に並び替えて返します。
ThenByDescendingメソッドはOrderByのソート結果をさらに別のキーで降順に並び替えて返します。

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    //身長
    public int Height { get; set; }

    public static IEnumerable<Person> GetPerson() 
    {
        return new List<Person>()
        {
            new Person()
            {
                Name = "ペン太",
                Age = 25,
                Height = 175,
            },
            new Person()
            {
                Name = "ペン子",
                Age = 30,
                Height = 150,
            },
            new Person()
            {
                Name = "ホゲ助",
                Age = 50,
                Height = 165,
            }
        };
    }
}

static void Main(string[] args)
{
    //※複数の条件を指定したい場合、2個目以降の条件はThenByで指定する

    //昇順
    var thenBy = person.OrderBy(p => p.Age)  
                       .ThenBy(p => p.Height)
    //降順
    var thenByDescending = person.OrderBy(p => p.Age)
                                 .ThenByDescending(p => p.Height);
}  

Reverse

Reverse メソッドはシーケンスの要素の順序を反転します。

//1~9のシーケンス生成
IEnumerable<int> nums = Enumerable.Range(1, 9);
nums = nums.Reverse();   // ⇒ 9, 8, 7, 6, 5, 4, 3, 2, 1

Leave a Reply

Your email address will not be published. Required fields are marked *