自作クラスをListに複数入れて自在に操作しよう (C#)


#背景
とあるコードを書いていた際に複数の型変数を一纏めにして扱いたい、加えて、いくつのデータを扱うのか不確定なため、可変長に扱いたい、というシチュエーションに出会い、こんなかんじだろー、で書いていたら全然的外れでとても時間を溶かしたので、自身のまとめとしても書き留めた。
あと,classもカプセル化しており、カプセル化したclassからのデータの取り扱いについても書き留めている。


#環境
- Mac (macOS Big Sur 11.2.1)
- Visual studio for mac (8.9.8)


#使用言語
C# (Ver 9.0)


#対象者
- 自分で用意したclassをlistに入れて扱いたい人
- classをカプセル化したい人

#メリット
自在にlist内のプロパティを取り扱える


#書き方(言語化)
*前提条件: 今回は6人の生徒を160cmを基準にグループ分けして、体重が一番重たい人を探したいと思います。

####1. クラスを用意する
####2. クラスをカプセル化する
####3. 与えられた人数分ループを回す
####3.1. ループ内でStudentクラスのインスタンスを毎回生成する
####3.2 身長を与えられるので、身長を基準値によってlistに振り分ける
####4 体重と体重がconsoleから与えらるので、ListのFindメソッドで対応しているIdの人を見つけて割り当てる
####5 連想配列を背が高いグループと背が低いグループで両方に用意する
####6 ListのFindメソッドで一番体重が重たい人を見つける(Sortでもよかったんですが、今回はしていません。また次回)
####7 console.logで出力用に各値を変数に格納する
####8 イザ、出力!!!!!

```c#:Program.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design;

namespace class_capule
{
    class Student
    {
        //クラス自体の変数は下記の4行で定義
        private int id;
        private string name;
        private int weight;
        private int height;

        // 下記の4行でStudentクラスの変数に直接アクセスできない様にカプセル化
        public int Id { get; set; }
        public string Name { get; set; }
        public int Weight { get; set; }
        public int Height { get; set; }
    }

    class Program
    {
        static void Main()
        {
            //渡されるデータが幾つなのかはコンソールから渡す
            var N = int.Parse(Console.ReadLine());

            int[] represent = new int[2];
            const int standard = 160;

            //今回は身長によって2つのクラスに分ける
            var listH = new List<Student>();
            var listL = new List<Student>();

            //渡されたN回数分をループで回す
            for (int i = 1; i <= N; i++)
            {
                //Ver. 9.0からStudentクラスをインスタンス化(newだけで以下のクラス名は省略できる)
                Student src = new();

                //コンソールからまず身長が渡されるとする
                int studentTall = int.Parse(Console.ReadLine());
                string hoge = studentTall >= standard ?  "High": "Low";

                //Student型の変数srcに新規内容として格納(iが出席番号)
                src.Id = i;
                src.Height = studentTall;


                //基準の身長で入れるリストを分ける
                if (hoge == "High")
                {
                    listH.Add(src);
                }
                else
                {
                    listL.Add(src);
                }
            }

                //体重がコンソールから入力される(半角スペース区切りで1行の入力)
                int[] weightArr = Array.ConvertAll(Console.ReadLine().Trim().Split(' '), int.Parse);

                //名前がコンソールから入力される(半角スペース区切りで1行の入力)
                string[] nameArr = Console.ReadLine().Trim().Split(' ');

                for (int i = 1; i <= N; i++)
                {
                    //身長によって入れているListが異なるので条件分岐にて振り分ける
                    //その際に出席番号としてidをclassで持たせているので
                    //そのidがListに入っているStudentクラスにあるかどうかを判定する

                    //listのメソッドのFindメソッドを利用して、
                    //その中でラムダ式にて該当idを探す ←これ大切です‼️‼️‼️‼️‼️
                    if (listH.Find(x => x.Id == i) != null)
                    {
                        //コンソールから取得した体重と名前をFIndメソッドで見つけたidのクラスに付与する
                        listH.Find(x => x.Id == i).Weight = weightArr[i];
                        listH.Find(x => x.Id == i).Name = nameArr[i];
                    }
                    else if (listL.Find(x => x.Id == i) != null)
                    {
                        //コンソールから取得した体重と名前をFIndメソッドで見つけたidのクラスに付与する
                        listL.Find(x => x.Id == i).Weight = weightArr[i];
                        listL.Find(x => x.Id == i).Name = nameArr[i];
                    }

                }

            Dictionary<string, int> dictHighList = new()
            {
                { "studentId", 0 },
                { "heaviest", 0 },
            };
            Dictionary<string, int> dictLowList = new()
            {
                { "studentId", 0 },
                { "heaviest", 0 },
            };

            // 各グループの一番体重の重い人を調べる
            for (int i = 1; i <= N; i++)
            {
                // 各グループに存在するID で一番体重が重たい
                if (listH.Find(x => x.Id == i) != null
                    && listH.Find(x => x.Id == i).Weight > dictHighList["heaviest"])
                {
                    dictHighList["studentId"] = listH.Find(x => x.Id == i).Id;
                    dictHighList["heaviest"] = listH.Find(x => x.Id == i).Weight;

                }
                else if (listL.Find(x => x.Id == i) != null
                    && listL.Find(x => x.Id == i).Weight > dictLowList["heaviest"])
                {
                    dictLowList["studentId"] = listL.Find(x => x.Id == i).Id;
                    dictLowList["heaviest"] = listL.Find(x => x.Id == i).Weight;
                }
            }

            int highHeight = listH.Find(x => x.Id == dictHighList["studentId"]).Height;
            int highWeight = listH.Find(x => x.Id == dictHighList["studentId"]).Weight;
            string highName = listH.Find(x => x.Id == dictHighList["studentId"]).Name;

            int lowHeight = listL.Find(x => x.Id == dictLowList["studentId"]).Height;
            int lowWeight = listL.Find(x => x.Id == dictLowList["studentId"]).Weight;
            string lowName = listL.Find(x => x.Id == dictLowList["studentId"]).Name;

            Console.WriteLine("下記が出力結果です");
            Console.WriteLine($"{standard}以上の一番重たい人:{highName} 身長:{highHeight}cm 体重:{highWeight}kg");
            Console.WriteLine($"{standard}以下の一番重たい人:{lowName} 身長:{lowHeight}cm 体重:{lowWeight}kg");
            Console.ReadKey();
        }
    }

}
```

<*入力結果*>

```terminal:terminal
6
150
165
162
158
170
147
55 70 60 78 65 81
Keiko Toru Yumiko Sjinji Yuki Satoshi
下記が出力結果です
160以上の一番重たい人:Satoshi 身長:170cm 体重:81kg
160以下の一番重たい人:Toru 身長:151cm 体重:70kg

```

#まとめ
なんだか、自作のクラスをlistに入れていって探すだけ、というお題目だったんですが、気づいたらとても長いコードになってしまいました。(反省)
もう少し切り分けて書いてもよかったかもしれません。
また気づいた点や覚書きが必要そうなことがあれば書きたいと思います。