大復活C#学習_Listを使って合計と平均値を求める

f:id:yasui_swift:20201218164234p:plain

Listを用いた平均と標準偏差の計算


お年玉プロジェクトへはなかなか到達しない。まだまだ遠い道のりが続く。

今回はジェネリックなコレクションであるListを使ったプロジェクトを作り、Listの初歩的な使い方を学習する。入門なので、今回はデータ数をはじめに与えて使い方を学習する(文末<覚え書き>参照)。

配列とは違う使い勝手に慣れることを目的とする。ソートして昇順、降順の表示や最大値、最小値の表示も学ぶ。

メインは画面表示とListを用いた入力、集計、計算結果のみを表示する。

画面と入力・計算はそれぞれ別のクラスとしてメソッドを記載する。

【学習のポイント】

・p = Console.ReadLine(); //(Console.Readline();は文字型stringで入力される)

・int x = int.Parse(p); //文字列を整数に変換.型を変換することをキャストという.

・List<int> numList = new List<int>(); //numListという名前のリストを作る

・numList.Add(w);  //Listにwを追加する

・numList.Sort();  //昇順にソートする 

・numlist.Reverse();  //降順にソートする

・numList.Count  //Listの長さ(件数)を数える

・ Math.Pow((numList[a]-mean),2.0);//べき乗の変数はdouble型でないとエラーになる

・Math.Sqrt(bunsan_calc1 / b);//平方根も変数はdouble型

 【リストの作成コード】

class CalcList
{
 public CalcList() { }
 public void Calclist()
 {
  //Listの件数を入力する 
  string p; //件数はstring型、あとでint型に変換
        string value; //値もstring型、あとでint型に変換
  int w;
  var sum = 0;
  float mean;
  int maxW = 0;
  int minW = 0;

  Console.Write(" 件数を入れてください__ "); //はじめに件数を入れる
  p = Console.ReadLine(); //(Console.Readline();は文字型stringで入力される)
  Console.WriteLine(); //

  int x = int.Parse(p); //文字列を整数に変換が必要

  //Listの作成
  List<int> numList = new List<int>(); //numというnumListを作る
  for (int n = 0; n < x; n++)
   {
    Console.Write(" " + (n + 1) + "番目の整数の値を入れてください__ ");

    value = Console.ReadLine();//値の入力
    w = int.Parse(value);
    numList.Add(w); //Listに加える

    sum +=  w; //合計を求める

   }

  float y = x;
  mean = sum / y;

  //昇順にソートする
  Console.WriteLine();
  Console.WriteLine(" 昇順にソートの結果を表示します");
  numList.Sort();

  for (int i = 0; i < numList.Count; i++)
  {
   Console.WriteLine(" " + numList[i]);
   maxW = numList[i];
   minW = numList[0];
  }

  //標準偏差を計算する
  double bunsan_calc1 = 0;

  double sd = 0;

  for (int a = 0;a<numList.Count;a++)
  {
   bunsan_calc1 += Math.Pow((numList[a]-mean),2.0); //2乗して加算
  }
  double b = numList.Count;
  sd = Math.Sqrt(bunsan_calc1 / b);

  Console.WriteLine();
  Console.Write(" 合計 = {0}", sum);
  Console.Write(" 平均 = {0:##.##}", mean);
  Console.WriteLine(" 標準偏差 = {0:##.#}",sd);
  Console.WriteLine(" 最小値{0}, 最大値{1}", minW, maxW);
 }
}

【画面の表示】

class GamenConsole
{
 public void gamenConsole()
 {
  Console.WriteLine();
  Console.WriteLine(" ================================");
  Console.WriteLine(" 平均値の計 算:整数(Listを使用)");
  Console.WriteLine(" ================================");
  Console.WriteLine();
 }

【メイン】

class Program
{
 static void Main( )
 {
  GamenConsole gamen = new GamenConsole();
  gamen.gamenConsole();
  CalcList calc = new CalcList();
  calc.calclist();
 }

f:id:yasui_swift:20201219075634j:plain

線路は続く

*********

これで今度の試験の採点は平均点と標準偏差が計算できるようになった。

できれば最初に件数を入れないで数値だけどんどん入れてリストを作り、それぞれの学生の偏差値も計算できるといいけれどなあ。まだ出来ない。こんど考えよう(お年玉プロジェクトをさきに作らないといけないし)。でも、名前と点数が紐づけられていないと実用性はないな。

*** Listのメソッド ***

Add(値)//最後尾に要素を追加

Insert(位置、値)//指定した位置に要素を挿入

Remobve(値)//指定した位置の要素を削除

RemoveAtClear(インデックス) //指定したインデックスの要素を削除

Clear()//すべての要素を削除

IndexOf(検索する値)//要素の位置を検索

Contains(検索する値)//要素の有無を調べる

Sort()//昇順にソート

Reverse()//降順にソート

f:id:yasui_swift:20201219075723j:plain

海辺を走る

*** <コレクションに関する覚え書き> ***

C#ではプログラムで複数のデータを扱う場合、配列とコレクションのふたつの方法で取り扱う。配列は処理スピードが早いが、初期化時にデータ数を指定する必要がある(固定長)。

コレクションはプログラムの途中でデータの数を変更でき、初期化時にデータの数を指定しなくてもよい利点がある。C#には歴史的な経緯で非ジェネリックジェネリックなコレクションがあるが、現在では新しいジェネリックを使用すべきで、非ジェネリックなコレクションを用いる利点はない。ジェネリックなコレクションには、List、Dictionary、SortedList、SortedDictionary、Queue、Stack、LinkedListがある。

大復活C#学習_コンソールウィンドウの表示

f:id:yasui_swift:20201206155931p:plain

コンソールウィンドウの表示

学習を始める。

始めにコンソールウインドウの表示について学ぶ。

Console.CursorVisible = true;  //カーソルの表示。falseにすると表示されない

Console.Title = "BMIの計算";//コンソールウィンドウのタイトル
Console.SetWindowSize(40, 10); //コンソールウィンドウのサイズ
Console.SetWindowPosition(10, 50);//コンソールウィンドウの位置

Console.BackgroundColor = ConsoleColor.White;//コンソールウィンドウの背景の色
Console.ForegroundColor = ConsoleColor.Blue; //文字の色
Console.Clear();//背景の色を変更。

//これを入れないと文字の背景だけ変更になる

Console.WriteLine("==========");
Console.WriteLine("  BMIの計算  ");
Console.WriteLine("=============");

大復活C#学習準備_9

このC#の学習準備のブログもそろそろまとめに入り、次のテーマごとのステップ学習にレベルアップしなければならない。準備段階として、プログラムを書くための最低限の目標であるクラスの作成について記録しておく。

f:id:yasui_swift:20201124072815p:plain

基本的なクラスの作り方を学ぶ。目標はお年玉プロジェクトで「孫」の「お小遣い」を表示する画面に名前とお小遣いの額を一行に表示するコードが書けるようになることとする。学習の内容は二次元配列を使うこと、if文、配列の内容を繰り返し表示するforeachを使うことを要件とした。これで学習準備を一区切りとしたい。

多次元配列は単純化のために2次元を使った。要素は「孫の名前」の文字列と「お小遣い」の数値としたかったが、文字列と数値の混在する配列の作り方がわからず両者ともに文字列にして扱うことにした。あとで計算時に数値は文字列から整数に変換することにする。もし、今後、文字列と数値が混在する多次元配列の扱い方がわかれば改めて作り直すことにしたい。(後註:配列は同一データ型でしかつくることができない.Listならできるのかもしれないが、未学習)

はじめに新しいクラスの追加は画面右側のソリューションエクスプローラーのプロジェクト名(ここではOtoshidamaApp)を右クリックして「追加」を選択し、続いて「新しい項目」、次に最上段の「クラス」を選び名前をつけて追加する。//ここではOkodukaiと入力した(これで新しいクラスはOkodukai.csとなる)。

f:id:yasui_swift:20201124074302p:plain



f:id:yasui_swift:20201124074331p:plain

クラスを設定したら、メソッドで使用する変数の初期値を定義する。

次にメソッドを作る。ここでメソッド名を、

public void Gamen3( ) //ここでも( )のうしろには;はつけない

とした。

次に配列の宣言である。多次元配列の初歩なので簡単のために3組 × 2要素の配列で学習した。

 

すでに記録した一次元配列の作り方では多次元配列は作れない。コードの書式(というか文法か?)は、

string[ , ] hairetsumei = new string[n,m]{{"ここ","そこ"},{"どこ","あそこ"},{"ほれ","あれ"}};

//nは要素の組数、mは一組のなかの要素数。この場合はnが3,mが2となる//。要素は波括弧でくくり、全体も波括弧でくくる。最後に;をつける。

 

繰り返し処理のforeachは2次元の場合は配列の[0,0],[0,1],[1,0],[1,1]・・・の順に一つのデータとして扱われる。

ここで文字列二次元配列では

foreach(string in Hairetumei)

{

}

として配列の要素を順番に呼び出す。一組の要素をそろって呼びだすことができるのだろうがまだ不明なので、苦労した。if文で奇数番目と偶数番目を判別するめんどくさい方法でしかいまのところできない。if文は簡単だが、括弧の使い方が独特。

if (      ) //( )のあとには;はつけないので注意。

{ 条件1}

else

{ 条件2 }

 

最後にProgrma.csのメインメソッドにお小遣い画面の表示のための新たなインスタンスをつくり画面表示ができるようにする。//以下をProgram.csに追加。

Okodukai okodukai = new Okodukai( );

okodukai.Gamen3( );

 

f:id:yasui_swift:20201124074431p:plain

f:id:yasui_swift:20201124074459p:plain

これでなんとか目的を達成(上段の画面参照)。文字列の改行の設定に頭を悩ました。単純なことなのにずいぶんと時間がかかってしまった。でも目的である、一行に名前と額を表示すること、ができたのでよしとする。ベテランからみればアホなことしているなあと笑われるだろうが、独学なのでしょうがない。

(いろいろ行事や仕事があってなかなか学習が進まないが、なんとか初歩の初歩は達成したように思う。これで、ようやくつぎのテーマごとの学習に進める)

大復活C#学習準備_8

いざプログラムを書こうと思うと、なかなか書けない。教則本を読んでわかったように気がしていても見るとやるでは大違い。文法の基礎知識を理解したと思っても、自分で考えながら実際の作業をしないと一行のコードも書けない。身についていないのだ。英単語を覚えても英会話ができないのと一緒だ。その意味では、あせらずこつこつやるしかない。教科書は基本的なことからだんだんと複雑な作業の説明へとすすみ、便利な機能や高度な機能へと学習がステップアップしてゆくが、頭でっかちの砂上の楼閣で、地に足がついていない。少しづつ冷汗をかきながらあきらめずに続けないとならない。

とりあえず初期画面を表示するクラスを作る。

 最初に画面の構成を決めて初期画面のクラスを作り、メインメソッドのあるクラスは単純で簡素な構成にしてコンストラクタを用いて初期画面クラスのインスタンスを作りメソッドを実施することにする。これが第一段階。

次は別に登場人物の特性を示す画面を作る。配列を用いて登場者の名前、年齢、所持金、欲しいものとその金額を画面に示す。貯金は1000円の固定する(後程変更する)予定。

 

f:id:yasui_swift:20201112062821p:plain

初期画面(違いがわかるように少しいじる)

f:id:yasui_swift:20201112062924p:plain

メインメソッドのクラス

f:id:yasui_swift:20201112063000p:plain

練習用コメント付きの初期画面クラスの作成

f:id:yasui_swift:20201112071454p:plain

初期画面クラス前半部分

f:id:yasui_swift:20201112071529p:plain

初期画面クラス後半部分



 

大復活C#学習準備_7

C#を学習するにあたって、これまでかなりの数の入門書を眺めてきた。どの本もそれぞれに一長一短があり、いまのところこの一冊さえあれば十分という本はない。おそらくそんな教則本は存在しないのだろう。

初心者には荷が重いほどあれこれ詳しく書いてある本やすきまなく細かい字でびっしり書いてある本は辞書として使うにははよいが、ひとつひとつ積み上げながら学ぶ手順書としては息苦しい。省略しすぎてエッセンスだけだと、読んでいる間は解ったような気分になるが、本を閉じるとまるで解っていないことに気づく。

青やオレンジの多色刷りも時にはかえって見にくくなってしまい気持ちが疲れる気がする。

コードの解説はあるが出力結果のない書物も多い。コードの記述やコンソールへの結果の出力は具体的に目に見えるように図や表で掲載してある方が学びやすい。

あとはただ学ぶ。ひたすら学ぶ。学びつづける・・・。

しかし受験勉強ではないので孤独に本をみて見本のコードを読解する作業ばかりでは楽しくない。コメントやコラムや話題あるいはほどよい挿絵などがあったほうが安らぐ。

山積みになるばかりなのでそろそろ入門書探しはやめにして、教科書を参考にしながら自分で考える訓練をすることにする。

f:id:yasui_swift:20201108075038j:plain

図書館で借りた「基礎からしっかり学ぶC#の教科書ー改訂新版」(日経BP、2019)

 ○手順を考える

まずは手順を考える訓練をする。

どのようなストーリーでプログラムを展開するか、からはじめたい。とりあえずプロジェクトに登場する事項(変数)すべてをコードであらかじめプログラムに書き込むことにする(次のステップではConsole.ReadLineで入力するか、配列を用いて外部から入力するようにしたい)。

前回書いたお年玉プロジェクトを下敷きにして、組み立てることにする。

1.プログラムのあらすじを考える

2.フローを考える//はじめは単純にしてカプセル化や継承、多態性を学習する

3.登場人物を考える//ここでは3人

4.お年玉の額を決める//年齢によって額を決めることにする。

5.貯金の額を決める。//あらかじめ1000円としてしまう。

6.欲しいものとその値段を決める//残高がマイナスにならないようにする。

7.子供たちの反応を示す。

8.表示する画面の出力形式(見た目)をきめる。

9。以上を踏まえて、何をメインにして何をクラスにするか振り分ける。

孫がお年玉を年齢に応じてもらい、買いたいものを買おうとするが、親が無駄遣いのないようにその一部を貯金してしまい。その結果欲しいものが買えたかどうかを判定して最後に孫たちの反応を出力するプロジェクトを作ることにする。

大復活C#学習準備_6

 独習・独学での学習には体力と気力がいる。座右の書として、そばにおいて繰り返し調べる資料が必要だ。電子書籍に慣れている若者であれば紙の書籍は不要だろうが、紙には紙の利点がある。

つい最近手にした参考書で気づいたことがある。これまで見てきた手持ちのC#の入門書はどれもコンソール画面(CUI)を用いてプログラム作成を解説している。これとは違って最初からWindowsフォームを用いて解説している書籍もある。すなわち入門書には、説明の仕方が違う二種類の本があるのだ。

f:id:yasui_swift:20201107141929j:plain

GUIによる参考書2冊

 「ゴールからはじめC#(改訂版)(菅原朋子著、技術評論社、2019)」は始めはGUIを用いており、途中でCUIの例題もでている。「10日でおぼえるC#入門教室(arton著、翔泳社、2013、最近改訂版がでたようだが、未確認)」はほとんどすべてGUIを用いて説明している。たしかにCUIだけの入門解説は一見して無味乾燥で、画面がさびしい感じがする。その点ではGUIでの入門が華やかで違和感がないけれど、画面表示のコードは難解だ。

個人的には、入門はCUIによってしっかり基礎的な文法やプログラムの成り立ちを身に着けるほうが挫折しないですむような気がする。グラフィック画面表示のためのコマンドがないぶん、コードがやさしいからだ。現実的には、CUIだけでのプログラミングはあり得ないだろうが、これから学ぼうとする初心者にはCUIを用いたほうがよいと思う。いずれ上達すれば画面に複雑なレイアウトを表示するプログラムを作成することに至るのだろうから、初心者はまず続けられるかどうかが肝心だ。

次の学習準備としては前回のお年玉プロジェクトに手を加え、保護者のピンハネ(無駄遣いしないための貯金)を加えてまごっちの反応を表すように改編しようと思う。

大復活C#学習準備_5

 

C#が新しい言語だといってもすでに開発から20年近くたっている。本屋に行ってみると棚にはたくさんの本が並んでいるが、ITやプログラミング関連ではスマートフォンAndroid)の使い方やエクセル入門と並んでPython関連の学習本が圧倒的な存在感を示している。CやC++の本も少しは見つけることが出来るが、C#についてはきわめて少ない。

Pythonがブームなのは機械学習に容易にチャレンジできるからだろう。C#やSwiftもPython同様にオブジェクト指向言語なのに人気がないのは難解だからに違いない。

手に入れた古本や「超」入門を拾い読みしてみると、たしかに難解だ。オブジェクト指向プログラミング言語は以下の3つの特性を供えている、という。

カプセル化(データの隠蔽)

・継承

多態性ポリモーフィズム

これをオブジェクト指向プログラミングの三本柱という。他の言語の入門書の第1章でいままでこの単語に遭遇した記憶がない。初心者は解説書の最初に書いてあるこの3項目を目にするだけで怖気づいてしまう。意味がわからないからだ。すでにこの瞬間に挫折してしまうのが目に見えるようだ。

少しだけ本を読んで感じたのは、変数やデータ型、演算子、制御文、配列など、他の言語やアプリケーションとほとんど違わないように思える。方言の違いくらいだろうか。

三本柱が難解だ。

本質は、クラスとオブジェクトにあるように直観する。

クラスとオブジェクトを理解するために、はじめはメイン(Main( ))だけのクラスを作って理解を深めたい。

 遊び心をくすぐる時刻表示のプロジェクトを書いてみた(出典は「猫でもわかるC#プログラミング(初版)」、2007年)。

f:id:yasui_swift:20201102103704p:plain

時計

f:id:yasui_swift:20201102103731p:plain

clockSampleのコード

名前空間は ClockSample。

クラスは clockSampleのみで、メソッドはMain( )のみ。Main( )にはstatic とpublic が付いている。
コンソールへの表示コードはただ本の記載をまる写しただけだ(これについては、ここでは勉強しない、ただの受け売りで済ませる。いずれGUIで学習する予定)。見た目は一見、まがまがしいが、内容はいたって単純な、制御文if elseだけのプロジェクトだ。

パソコンの画面左上に時刻を表示する小さなウインドウが開く。何かのキーを押すと消える。

学習】ここではClockSampleというフォルダ(プログラムの保存場所)にclockSampleという名前のクラス(class)が作られた。画面右端のソリューションエクスプローラに表示されている(スクリーンセーバによって撮った写真を参照)。

f:id:yasui_swift:20201102143946p:plain

ソリューションエクスプローラの部位

 C#によるアプリケーションの開発には「Microsoft Visual Studio」を使用している。Visual Studioにおいてアプリケーションは「プロジェクト」という単位で管理される。プロジェクトの中には、そのアプリケーションで必要となるクラスのファイルが生成される。

通常システムは複数のアプリケーションやクラスライブラリから構成され、複数のプロジェクトを集めて「ソリューション」という単位で管理される。

プロジェクトを作成すると「Program.cs」というファイルが生成され、プログラムで使用するプログラムのファイル、テキストファイル、画像ファイルなどが一覧形式でここに表示される。

カプセル化通常変数はアクセス修飾子(publicやprivateなど)を使って他のクラスからクラス内部のメンバにアクセスできるかどうかを決めている。カプセル化とは隠蔽を意味する。外からメンバ変数におかしな値を入れられないようにして、利用してほしい機能だけを使えるようにするのが目的である。

 public   :すべてのクラスからアクセス可能

 private :自分のクラス以外からはアクセス不可能

 protected :自分のクラスまたは派生クラスからのみアクセス可能

アクセス修飾子は通常、変数の定義やメッソドの定義の先頭に記載する。

 public int bodyWeight ; //  体重の定義

 private sti hisName ; // 彼の名前

 オブジェクト指向では、仕組みが見えなくても希望する処理が行えるようにすることを隠蔽化(カプセル化)という。「中身(内部実装)がどうなっているかを隠蔽し、可能な操作と属性(外部仕様)のみを公表する」という思想があり、この”可能な操作”をメソッド(method)、”属性”のことをプロパティ(property)という。上記の、アクセス修飾子による制限もカプセル化の一例である。

 

継承:クラス間で重複している部分を取り出して新しいクラスを作り、プログラムの重複をなくす仕組み。

  継承を使ったクラスの書き方

  class 派生クラス:基本クラス

 {

         // ここにメソッドなどを書く

   }

 継承したメソッドの一部を変更したい場合はメソッドオーバーライドを用いる(後述)。基本クラスのメソッドにvirtual キーワード、派生クラスのメソッドにoverrideキーワードをつける(後述)。

多態性ポリモーフィズム)の理解にはもう少し学習が必要だ。

次回は、ここで示した事項をクラスとオブジェクト(インスタンス)を絡めて学びたい。

例】クラスの継承を作ってみる。初めてなので、誤りは後程訂正する予定(習うより慣れよぉ!)。

f:id:yasui_swift:20201103190332p:plain

お年玉プロジェクトの表示結果

コンストラクタの訓練

f:id:yasui_swift:20201103190450p:plain

(続き)

f:id:yasui_swift:20201103190509p:plain

プログラムのメイン部分は以下。

f:id:yasui_swift:20201103190548p:plain

学習】現在理解している手順について略記しておく。

1.クラス(class)でインスタンス(オブジェクト)を作成するときは最初にclass名と同じコンストラクタ(建設者の意味)を記載する。自分でコンストラクタを記載していない場合にはコンパイラが自動で引数も処理もないデフォルトコンストラクタを生成している。自分でコンストラクタを記載した場合はデフォルトコンストラクタは生成されない。できればコンストラクタを作成する際には( )にこれから用いる変数を定義しておいた方がよい。またコンストラクタを宣言する前に引数の型定義(intやstrやdoubleなど)を行っておく。

コンストラクタとはクラスがインスタンス作成時に一度だけ実行したい処理(クラスの初期化処理など)を定義することである。先の「時計」のプロジェクトには記載がない。「お年玉」では14行目がコンストラクタだ。

(記載例) 

       class Sample //これがコンストラクタのもととなるクラス

      {

    public string name;

         public int  age;

         publiac double number;

   // 次の行がコンストラクタを表す

        public Sample←class名と同じ名前する(string name,int age, doublr number )

    {

        //ここに引数の初期値やメソッドを記載する。

      }

         }

 

2.Main()メソッドを実行するclassには、そのプロジェクトの最終結果を表示する内容をコードする。変数定義にはこれから行う内容で使用する基本となる変数(名前や数値や住所など)や定数(倍率など)を記載しておく。原則としてこの学習中は変数の宣言はすべてpublicにしておきエラーが生じないようにする。(追記:例外として、set、getを用いたプロパティではprivateを用いる)

3.Main( )メソッドのclassにメソッドを返すために新たに”ファイル内に追加したclass”(とりあえず「子クラス」と呼ぶことにしておく。正式名がわかれば訂正する)にはたくさんのメソッドは記載せず2ないし3本位にとどめる。Main( )メソッドのあるclassにはコンストラクタによって子クラスの基本クラスから作成した派生クラスを用いてメソッドを記載して結果を表示する。

記載例)派生クラスの作り方

 Sample  newSample = new Sample();  //newSampleが派生クラスとして作られる

 

とりあえず、ここまでが現在のところ理解している、クラス、インスタンス、コンストラクタの内容だ。もう少しレベルが上がったらもっと手順として整理したい。

クラスは入れ物、オブジェクトは鋳型、鋳型を使ったできあがったものがインスタンスという理解だろう(未熟なので間違っていたら、ごめんなさいです)。