【C#】List型(リスト型)をつかいこなそう #5

スポンサーリンク

List型を使いこなしてきました!(多分)

今回はList型の要素が構造体だった時の使い方について紹介していきたいと思います。

今までの知識と組み合わせで行けるので、理解しましょう!

復習と前置きから行きます!

List型(リスト型)ってなに?

配列の1種ですね!

一言でいうと「登録型配列」かなぁ~!

いや「可長配列」でもいいかもしれません🎵

 

世の中もので例えるとバインダー的なw

定義の仕方は

A4サイズの紙(型、構造体、クラス)しか入れない、

バインダー(リスト型)を定義するって感じです。

前提の関数を定義

まずは初めにサンプル用のリストを定義しようと思います。サンプル作成用の関数を作成します。

GUIの作成

今回はこんな感じにしたいと思います。

サンプルリストを作成&上のテキストに表示し、ボタンに応じた要素を下のテキストに表示します。

②構造体の定義

今回の構造体は、整数値(int)、小数(double)、文字(string)の3つを定義します。

struct SampleStruct
{
    internal int SampleInt;
    internal double SampleDbl;
    internal string SampleStr;
}

今回のリストは関数内で作成して出力させるため、構造体の定義のみとします。

サンプルのリストを作る関数を作成

次にサンプルリストを作ります。(関数名:SetSampleListStruct)

今回引数には出力(out)を使って、サンプルのリストの結果を返します。

private void SetSampleListStruct(out List<SampleStruct> lstSample)
{
    //インスタンス生成
    lstSample = new List<SampleStruct>();
    lstSample.Clear();  //一旦 空にする

    int number = 3; //サンプルなので3つ登録
    Random rd = new Random(DateTime.Now.Millisecond);
    for (int num = 0; num < number; num++)
    {
        //参照渡しなのでインスタンスは作り直す
        SampleStruct tmp = new SampleStruct();

        //ランダムで数値を代入
        tmp.SampleInt = rd.Next(10, 100);    //2桁の数字

        //ランダムの少数点
        tmp.SampleDbl = Math.Round(rd.NextDouble() * 10.0, 2);  
        //ランダムの文字(ASCIIコードの範囲)                
        tmp.SampleStr = ((char)rd.Next(0x21, 0x7F)).ToString(); 

        //登録
        lstSample.Add(tmp);
    }
}

numberを変更すればリストの数は変更可能です。今回はListの数は3つです。

補足

今回文字をランダムにするために、0x21~0x7Eの間の数値を使用します。

この数値は、下記ASCIIコードを元にしています。

下記、白部の部分の範囲を使います。

白部のエリアの範囲でランダムの数字を出力し、文字列に変換します。

サンプルのリストを表示する関数を作成

次にサンプルリストの表示を作ります。(関数名:DispSampleListStruct)

private void DispSampleListStruct(List<SampleStruct> lstSample)
{
    //一旦リセット
    txtElement1.Text = txtElement2.Text = txtElement3.Text = "";

    //リスト分ループし、表示
    foreach (SampleStruct tmp in lstSample)
    {
        txtElement1.Text += tmp.SampleInt.ToString() + "\r\n";
        txtElement2.Text += tmp.SampleDbl.ToString("0.00") + "\r\n";    //小数点第2位まで
        txtElement3.Text += tmp.SampleStr + "\r\n";
    }
}

これで前準備完了です。

構造体から1つの要素(定義)のみを取得する

実は前置きの方が長かったですwこれで大半は終わっています!

では、早速1つの要素(定義)のみ取得してみましょう

Int型の要素(定義)を取得

サンプルのリストの構造体はInt型[SampleInt]とDouble型[SampleDbl]とString型[SampleStr]の3つで構成されています。今回は、SampleIntだけを抽出し、List<int>の形で取得しましょう!

流れは下記の通りになります。

  1. サンプルリスト作成
  2. サンプルリスト表示
  3. [SampleInt]を取得[抽出]し、List<int>の形で取得
  4. 取得した結果を表示
private void btnGetElement1_Click(object sender, EventArgs e)
{
    //サンプルリスト作成
    SetSampleListStruct(out List<SampleStruct> lstSample);

    //サンプルリスト表示
    DispSampleListStruct(lstSample);

    //リストから要素のint型を取得
    List<int> lstInt = lstSample.Select(x => x.SampleInt).ToList();

    //取得した結果を表示
    DispResultListINT(lstInt);
}

出来ました!事前に関数を作っていたので、関数を並べるだけですね。

あっっ!!取得した結果を表示する関数を記載忘れましたっっ!!

適当に作っちゃってください☆彡笑

他の要素を取得

他の要素も取得してみます。

簡単に言うと、定義とラムダ式の内容を変更するだけです。

ここに関してはほぼコピペなので画像だけにします。

ラムダ式の中身を(x => x.[変数名])にする事で取得したい変数を取得することができます。

List型の構造体の変数だけ取得して、平均/最大/最小を取得

リストに登録されている構造体のInt型の平均/最大/最小を取得してみたいと思います。

※処理時間的に平均/最大/最小を取得するならループで回した方がいいと思います。

LINQを使って各々を1行で取得してみます!

間に追記しました。過去の記事を含めた知識で、List型からLINQを使って構造体の平均、最大、最小を取得することができました。結果は下記の感じになりました。

DispResultAveMaxMin(double,int,int)の関数に関しては記載していませんが、画面の結果からどうなっているか推測してください。

移動平均をLINQを使って取得

最後に移動平均を取得したいと思います。

移動平均とは

移動平均は、時系列データ(より一般的には時系列に限らず系列データ)を平滑化する手法である。

移動平均 – Wikipedia

簡単に言うと、データをある区間(データ数)に区切って平均をとっていく方法です。

※投資している人は、テクニカル分析の1つとして使用していますね。

データとして、1~6があって、移動平均の区間が3の場合、

区間3の移動平均のデータとしては、【2,3,4,5】になります。

先ほどのInt型のリストを使って移動平均を求めてみましょう。

GUIの作成

先ほどのソフトにボタンを追加します。

左下のボタンを追加しました。

処理を書いていきます。

LINQを使って移動平均を計算

まずは処理の流れです。少し複雑です。

「LINQを使ってできるんだぞ」っていう例です。ラムダ式が混じるので頑張りましょう!

  1. 処理の回数(シーケンス数)を決める
  2. Int型の定義を抜き取って、ある要素の範囲だけを取得
  3. 取得した内容を平均
  4. 処理の回数分、2,3を繰り返す
  5. リスト型に型変更

1行でやりますがかなり見づらいです。。。

※人に見られるソフトなら分割することをオススメしますw

private void btnGetMvAve_Click(object sender, EventArgs e)
{
    //サンプルリスト作成
    SetSampleListStruct(6,out List<SampleStruct> lstSample);

    //サンプルリスト表示
    DispSampleListStruct(lstSample);

    //リストから要素のInt型から区間3の移動平均を取得する
    int section = 3;
    List<double> lstMvAve = Enumerable.Range(0, lstSample.Count - section + 1)
        .Select(seq => lstSample.Select(x => x.SampleInt).Skip(seq).Take(section)
        .Average()).ToList();

    //取得した結果を表示
    DispResultListDBL(lstMvAve);
}

結果は下記のとおりです。エクセルでも確認しましたが問題ありませんでした。

補足 各LINQ説明

処理回数(シーケンス数)を取得する

List<int>で取得できます。リストの中身は[0,1,2,…,n]です。

移動平均をする構造体の要素を抽出

今回は構造体のSampleIntを使います

リストの指定された範囲の平均を計算する関数を作る

SkipとTakeを使って、指定された位置からの特定の範囲のデータを抽出し、その平均を求めます。

移動平均のリストを作成する

Step1.Select()はイメージ的にはFor文だと思ってください。seqというのは[0,1,2…n]

区間が3の為、[0,1,2][1,2,3][2,3,4]…[n,n+1,n+2]の組み合わせの平均を取得します。

まとめ

今回で「List型を使いこなそうシリーズ」は最後ですw

最後は、構造体だったらとか移動平均を求める方法と2つのテーマについて書いてしまいました。

※本当だったら別々の方がよかったと後悔w

ただ分かった事として、リスト型を使いこなすうえで、LINQやラムダ式の理解が少なからず必要になってきます。

※そしてラムダ式は慣れないと正直見づらい。。。

◆リストの中が構造体で特定の定義のみ抽出したい時は、Selectを使う

◆移動平均はLINQとラムダ式のオンパレードw

最後までお付き合いありがとうございましたぁ~!!

コメント

タイトルとURLをコピーしました