meimaru’s blog

やってみて詰まったことを備忘録として残すブログ

【C#】LINQに慣れる2~LINQのメソッド~

前回の記事はこちらになります
meimaru.hatenablog.com

今回はLINQのメソッドをいろいろ使ってみようと思います。

前方・後方・部分一致検索

using System;
using System.Linq;

namespace Test.LINQ
{
    class SandBox
    {
        public static void Main(string[] args)
        {
            var sfcSoftTable = new SfcSoftTable();

            var softTitles = sfcSoftTable.SoftTable.Where(val => val.Title.StartsWith("星の"))
                                                   .OrderByDescending(val => val.Price)
                                                   .Select(val => val.Title + "   価格:" + val.Price);


            var softTitles2 = sfcSoftTable.SoftTable.Where(val => val.Title.EndsWith("デラックス"))
                                                   .OrderByDescending(val => val.Price)
                                                   .Select(val => val.Title + "   価格:" + val.Price);

            var softTitles3 = sfcSoftTable.SoftTable.Where(val => val.Title.Contains("カービィ"))
                                                   .OrderByDescending(val => val.Price)
                                                   .Select(val => val.Title + "   価格:" + val.Price);

            Console.WriteLine("前方一致:StartsWith");
            foreach (var title in softTitles)
            {
                Console.WriteLine(title);
            }

            Console.WriteLine("-------------------------------------");
            Console.WriteLine("後方一致:EndsWith");
            foreach (var title in softTitles2)
            {
                Console.WriteLine(title);
            }

            Console.WriteLine("-------------------------------------");
            Console.WriteLine("部分一致:Contains");
            foreach (var title in softTitles3)
            {
                Console.WriteLine(title);
            }
        }
    }
}

検索でおなじみのStartsWith、EndsWith、Containsを使い、

  • タイトルが「星の」から始まるソフト
  • タイトルが「デラックス」で終わるソフト
  • タイトルに「カービィ」が含まれているソフト

を探しました。
結果がこちら
f:id:meimaru:20200523184135p:plain
うまく取れたようです。
Containsですがよく使うList.Contains()の方は完全一致だったような・・・?
LINQの場合は部分一致になるようです。

候補値検索

特定の候補に一致するものを検索します。
これは先程も出たContains()を使います。

using System;
using System.Linq;

namespace Test.LINQ
{
    class SandBox
    {
        public static void Main(string[] args)
        {
            var sfcSoftTable = new SfcSoftTable();

            var softTitles = sfcSoftTable.SoftTable.Where(val => new int[] { 7500, 9500 }.Contains(val.Price))
                                                   .OrderBy(val => val.Price)
                                                   .Select(val => val.Title + "   価格:" + val.Price);

            foreach (var title in softTitles)
            {
                Console.WriteLine(title);
            }
        }
    }
}

7500円か9500円のソフトを探してみました。
f:id:meimaru:20200524132257p:plain
うまく検索できました。

範囲検索

特定の範囲に一致するものを検索します。
これにはメソッドはなく、演算子を使って操作します。

using System;
using System.Linq;

namespace Test.LINQ
{
    class SandBox
    {
        public static void Main(string[] args)
        {
            var sfcSoftTable = new SfcSoftTable();

            var softTitles = sfcSoftTable.SoftTable.Where(val => 11800 <= val.Price && val.Price <= 12000)
                                                   .OrderBy(val => val.Price)
                                                   .Select(val => val.Title + "   価格:" + val.Price);

            foreach (var title in softTitles)
            {
                Console.WriteLine(title);
            }

        }
    }
}

11800円~12000円のソフトを探してみました。
f:id:meimaru:20200524132818p:plain
結構ありましたね。
(雑感ですが、昔のゲームソフトは結構高価に感じますね。
しかし技術も作るコストも上がった今、こんくらいかそれ以上で売らないと
採算取れないんじゃないかと思うことがちょくちょくあります。)

単一の要素を取得する

単一の要素を検索するにはSingleメソッドを使います。
クロノ・トリガーを探してみました。

using System;
using System.Linq;

namespace Test.LINQ
{
    class SandBox
    {
        public static void Main(string[] args)
        {
            var sfcSoftTable = new SfcSoftTable();

            var soft = sfcSoftTable.SoftTable.Single(val => val.Title == "クロノ・トリガー");

            Console.WriteLine(soft.Title + "     価格:" + soft.Price);
        }
    }
}

f:id:meimaru:20200524163235p:plain

Singleメソッドを使う時の注意として、
「複数合致するものがある」または「条件に合致するものがない」場合、
InvaildOperationException例外が発生します。
「絶対に結果を1つだけ取得できる」状況で使うべきらしいです。

特定のプロパティを取り出して加工(Selectメソッド)

Selectメソッドでは範囲変数からプロパティを取り出し、
加工することができます。
ジーコサッカーを見つけて名前と価格を変えてみました。

using System;
using System.Linq;

namespace Test.LINQ
{
    class SandBox
    {
        public static void Main(string[] args)
        {
            var sfcSoftTable = new SfcSoftTable();

            var soft = sfcSoftTable.SoftTable.Where(val => val.Title == "ジーコ サッカー")
                                             .Select(val => new { Title = "非公式ソフト", Price = "    60,000円" });

            foreach (var val in soft)
            {
                Console.WriteLine(val.Title + val.Price);
            }
        }
    }
}

f:id:meimaru:20200524175700p:plain

重複を除去する

Distinctメソッドを使うと取り出したデータから重複を消せます。
メーカー名を重複を消して表示させてみました。

using System;
using System.Linq;

namespace Test.LINQ
{
    class SandBox
    {
        public static void Main(string[] args)
        {
            var sfcSoftTable = new SfcSoftTable();

            var soft = sfcSoftTable.SoftTable.OrderBy(val => val.Maker)
                                             .Select(val => val.Maker)
                                             .Distinct();

            foreach (var val in soft)
            {
                Console.WriteLine(val);
            }
        }
    }
}

f:id:meimaru:20200524180406p:plain

グループ化

GroupByメソッドを使うと特定の項目でグループ化することができます。
メーカーでグループ化し、チュンソフトまたはアトラスのソフトを
取り出してみました。

using System;
using System.Linq;

namespace Test.LINQ
{
    class SandBox
    {
        public static void Main(string[] args)
        {
            var sfcSoftTable = new SfcSoftTable();

            var soft = sfcSoftTable.SoftTable.GroupBy(m => m.Maker);

            foreach (var maker in soft)
            {
                if (maker.Key == "チュンソフト" || maker.Key == "アトラス")
                {
                    Console.WriteLine($"[{maker.Key}]");

                    foreach (var t in maker)
                    {
                        Console.WriteLine(t.Title);
                    }
                    Console.WriteLine();
                }
            }
        }
    }
}

f:id:meimaru:20200525154904p:plain

複数のキーでグループ化することも可能なようです。
メーカーと発売年でグループ化して
アトラスの発売年ごとのソフトを出してみました。

using System;
using System.Linq;

namespace Test.LINQ
{
    class SandBox
    {
        public static void Main(string[] args)
        {
            var sfcSoftTable = new SfcSoftTable();

            var soft = sfcSoftTable.SoftTable.GroupBy(m => new { Maker = m.Maker, Releae = m.ReleaseDate.Year });

            foreach (var g in soft)
            {
                if (g.Key.Maker == "アトラス")
                {
                    Console.WriteLine($"[{g.Key.Maker} - {g.Key.Releae}]");

                    foreach (var t in g)
                    {
                        Console.WriteLine(t.Title);
                    }
                    Console.WriteLine();
                }
            }
        }
    }
}

f:id:meimaru:20200525160536p:plain

この他にグループ化したのを更に絞り込んだり
複数のデータの結合をすることができるようです。

今回LINQのメソッドを少し使ってみましたが
ちょっと難しいというかややこしく感じました。
いろいろ使ってみたりして慣れて行こうと思います。