【第7章】データの再利用(執筆途中)
2022.06.15
ここまででプログラミングの3つの基本、順次処理、繰り返し処理、選択処理について学びました。これらについてはまだまだお話したいことがあるのですが、何度も言っているようにこのカテゴリーの目的は短期間でプログラミング的思考とコンピュータの基本を覚えていただくことなので、とりあえず先に進みます。ここからはヒンピュータならではの処理についてお話してゆきます。
[データの再利用]
コンピュータの得意技のひとつとしてデータの再利用があります(もちろんそのようなプログラムが可能という意味です)。電卓にもメモリーキーがありますが、コンピュータならもっと高度なことができます。まず、データの再利用について、円柱の体積を求めるプログラムを例に説明します。
図7-1.円柱の体積
円柱の体積は
または
で求められます。
①の考え方で書いたプログラムはこのようになります。
1:Dim pai As Single = 3.14159
2:Dim V As Single
3:Dim S As Single
4:Dim r As Single
5:Dim h As Single
6:Console.WriteLine()
7:Console.Write(" 底面の半径は?") : r = Console.ReadLine()
8:Console.Write(" 高さは?") : h = Console.ReadLine()
9:V = pai * r ^ 2 * h
10:Console.WriteLine(" 円柱の体積=" & V)
11:Console.ReadKey()
そして②の考え方で書くとこうなります。
1:Dim pai As Single = 3.14159
2:Dim V As Single
3:Dim S As Single
4:Dim r As Single
5:Dim h As Single
6:Console.WriteLine()
7:Console.Write(" 底面の半径は?") : r = Console.ReadLine()
8:Console.Write(" 高さは?") : h = Console.ReadLine()
9:S = pai * r ^ 2
10:V = S * h
11:Console.WriteLine(" 円柱の体積=" & V)
12:Console.ReadKey()
プログラムとしてはどちらも誤りではありません。実行結果はどちらも同じです(図7-2)。
図7-2.円柱の体積を求める
①のプログラムは必要な値、底面の半径、円周率、高さをいっぺんに計算式に入れて体積を求めるやり方です。②のプログラムは一旦底面積を求めてそれを変数に代入し、それに高さを掛けて体積を求める方法です。ここまでやってきたプログラムでおわかりいただけたと思いますが、変数に代入した値はプログラムで変数の値を書き換えない限りプログラム終了まで保存されます。②は9行目で変数Sに代入した底面積の値を10行目で再利用していることになります。底面の半径と高さを入力し円柱の体積を求めるプログラムとしてはどちらの組み方でもいいのですが、管理人はここは②の組み方をおすすめします。というのは、後に円柱の体積の他、たとえばこの円柱の表面積も求めたいという要求が出てきた場合、プログラムの改造(メンテナンス)が容易になるからです。
図7-3.円柱の体積と表面積を求める
上のプログラム例②を円柱の表面積も求める(図7-3)ように改造すると次のようになります。
1: ' 円柱の体積と表面積を求めるプログラム
2: ' 2022/07/10
3: ' B.S.I. Works Corp.
4:
5: ' 変数の宣言
6: Dim pai As Single = 3.14159 ' 円周率
7: Dim V As Single ' 体積
8: Dim S As Single ' 底面積
9: Dim SA As Single ' 側面積
10: Dim SS As Single ' 表面積
11: Dim L As Single ' 底面の円周
12: Dim r As Single ' 底面の半径
13: Dim h As Single ' 高さ
14:
15: Console.WriteLine("円柱の体積と表面積")
16: Console.WriteLine()
17: Console.Write(" 底面の半径は?") : r = Console.ReadLine() ' 半径入力
18: Console.Write(" 高さは?") : h = Console.ReadLine() ' 高さ入力
19:
20: S = pai * r ^ 2 ' 底面積計算
21: L = 2 * pai * r ' 底面の円周計算
22: SA = L * h ' 側面積計算
23: V = S * h ' 体積計算
24: SS = S * 2 + SA ' 表面積計算
25: ' 計算結果の表示
26: Console.WriteLine()
27: Console.WriteLine(" 円柱の底面積=" & S)
28: Console.WriteLine(" 円柱の側面積=" & SA)
29: Console.WriteLine(" 円柱の体積=" & V)
30: Console.WriteLine(" 円柱の表面積=" & SS)
31: ' 終わり
32: Console.ReadKey()
[配列]
変数に途中までの計算結果(処理結果)を代入(保存)してくことによって、それを後で再利用できることはおわかりいただけたと思います。ただ、ここでやったサンプルプログラム程度のものならコンピュータでなくてもメモリー機能付きの電卓が上手に使いこなせればできます。コンピュータならではのデータの再利用なら、これから学ぶ配列(*2)を使います。まず配列とはどういうものかを説明します。
ここにハイツ立山というアパートがあります。1号室は相沢さんの部屋、2号室には加藤さん、3号室には鈴木さん、4号室は空室で5号室には渡辺さんが住んでいます(図7-4)。これをプログラミング言語風に書くと
N=ハイツ立山(1)、Nの値は"相沢"
N=ハイツ立山(2)、Nの値は"加藤"
N=ハイツ立山(3)、Nの値は"鈴木"
N=ハイツ立山(4)、Nの値は""
N=ハイツ立山(5)、Nの値は"渡辺"
そして
ハイツ立山(4)="高橋"
とすると4号室には高橋さんが入居します。配列とはこのようなものです。
図7-4.配列の概念
配列を使用するには、Dimによる宣言が必要になります。
Dim 配列名(配列上限) As データ型
配列名は変数名と同じ規則で決められます。配列上限は正の整数です。データ型も変数の使用宣言と同じくInteger、Single、Stringなどです(*3)。たとえば
Dim uriage(5) As Integer
と宣言するとuriage(0)、uriage(1)、uriage(2)、uriage(3)、uriage(4)、uriage(5)の6つが、整数型データを扱える配列uriageとして使用できるようになります。
Dimの後ろの名前(この例ならuriage)を配列名、宣言後使えるようになるひとつひとつ(この例ならuriage(0)、uriage(1)・・・uriage(5))を配列の要素、配列の要素の( )の中の数字を添え字といいます。配列の要素は次のように変数のように使うことができます。
uriage(0) = 450
uriage(1) = tanka * suryo
ただ、このような使い方では配列を使う意味はありません。配列がその強みを発揮するのは繰り返し処理とデータの再利用です。
[配列を活用したデータの再利用]
これよりしばらく試験の成績処理のプログラムで説明します。学校の試験には良い思い出がないという方もいらっしゃると思いますが、しばらくお付き合いください。
今、試験実施後の結果が図7-5のようになっているとします。No.は出席番号、それぞれの右の数字は点数でか。これを入力し、平均を求め、各生徒の点数が平均とどれだけ離れているかを計算し表示します。その際上位1/4をS、下位1/4はFとします(図7-6)。点数の範囲は0~100点、平均は点数合計÷受験人数、欠席者は点数合計にも人数にもカウントしない、上位は(100+平均点)÷2を超える者、下位は平均点÷2未満の者とします(図7-7)。
図7-5.テストの成績
図7-6.テストの成績入力と結果表示
図7-7.上位者と下位者
このプログラムを実現するためには最初に平均を求めてから各点数-平均点を計算することになりますが、平均を求めるには受験者全員の点数を入力しなくてはなりません。その後に各点数との差を計算するのですから、入力した各点数をいったん保存しておく必要があります。ここではデータ保存と繰り返し処理両方に強い配列を使うことにします。
[プログラム概要]
図7-8.プログラムの大まかな流れ
図7-8に基づいて作成したプログラムは次のようになります。25~45行目は図7-8のstep1に、46~55行目はStep2に、56~82行目はStep3に相当します。
1: '**************************
2: '* テストの成績処理 *
3: '* 2022/07/15 *
4: '* by B.S.I.Works *
5: '**************************
6:
7: ' 配列と変数の準備
8: Dim tensu(50) As Integer ' 点数保存用
9: Dim ten As Integer ' 点数入力用
10: Dim gokei As Integer = 0 ' 点数保存用
11: Dim ninzu As Integer = 0 ' 受験人数
12: Dim heikin As Single ' 平均点
13: Dim s_line As Single ' 秀ライン
14: Dim f_line As Single ' 補習ライン
15: Dim i As Integer ' 配列添え字
16: Dim saigo As Integer ' 添え字最大
17:
18: ' プログラムの使用方法
19: Console.WriteLine("テストの成績処理")
20: Console.WriteLine("出席番号の後に点数を入れてください")
21: Console.WriteLine("入力終了時は999を入れてください")
22: Console.WriteLine("欠席はマイナスの点数を入れてください")
23: Console.WriteLine()
24:
25: ' 最初に全員の点数を入力
26:
27: For i = 1 To 50
28: Console.Write(" No." & i & "の点数 ")
29: ten = Console.ReadLine()
30: ' 999が入ってきたら入力終了
31: If ten = 999 Then
32: Exit For
33: End If
34: ' 点数が 0以上の時、合計に加算し配列に保存、人数もカウントアップ、
35: ' 点数が 0未満の時は点数を配列に保存するだけ
36: If ten >= 0 Then
37: gokei += ten
38: tensu(i) = ten
39: ninzu += 1
40: Else
42: tensu(i) = ten
43: End If
44: Next
45:
46: ' 入力終了後の処理
47: saigo = i - 1 ' 添え字の最後の値
48: ' 受験者数が 0でなければ平均を計算、秀の最低ライン、補習対象者の最高ラインを求める
49: If ninzu <> 0 Then
50: heikin = gokei / ninzu ' 平均計算
51: s_line = (100 + heikin) / 2 ' 秀の最低ライン
52: f_line = heikin / 2 ' 補習対象者の最高ライン
53: End If
54:
55: Console.WriteLine()
56:
57: ' 配列に保存した各点数の平均との差を計算、秀の対象か、補習の対象かを判別する
58: ' (受験者が 0のとき、変数saigoの値は -1になっているので
59: ' 次のFor ~ Nextループは実行されない)
60:
61: For i = 1 To saigo
62: Console.Write("No," & i & " ")
63: ' 欠席(在籍なし)の場合、次のIf~End Ifブロックは実行されない
64: If tensu(i) >= 0 Then
65: Console.Write(tensu(i) & " " & tensu(i) - heikin)
66: ' 点数が秀の最低ラインを超えていればSと表示
67: If tensu(i) > s_line Then
68: Console.WriteLine(" S")
69: ' 点数が補習対象者の最高ライン未満なら*と表示
70: ElseIf tensu(i) < f_line Then
71: Console.WriteLine(" *")
72: ' 秀でも補習対象者でもなければ何も表示しない
73: Else
74: Console.WriteLine()
75: End If
76: Else
77: Console.WriteLine()
78: End If
79: ' 表示10人分ごとにスクロールを一時停止
80: If i Mod 10 = 0 Then
81: Console.ReadKey()
82: End If
83: Next
84:
85: Console.WriteLine()
86: If ninzu <> 0 Then
87: Console.WriteLine("平均 " & heikin)
88: Console.WriteLine("受験人数 " & ninzu)
89: End If
90: Console.ReadKey()
[プログラムはわかりやすく書こう]
プログラムを詳しく解説する前に、今後のために先にこちらのお話をさせていただきます。
一度作ったプログラムは未来永劫そのままということは滅多にありません。使っているうちに不具合が見つかったり新たな要求が出てきて修正・改造の必要が出てくることは多々あります。そのような時、最初に作ったプログラムがわかりやすく書かれているのとそうでないのとでは、その後の作業効率が天と地ほどの差が出てしまいます。
VB2022に限って言えば、プログラム中に空行が何行あっても文法エラーにはなりません。そこで上のププログラム例では、図7-8の流れに従って各stepをひとかたまりにしてstep間に空行を入れました。
そして行頭や行の途中に '(ハングルクォーテーション)がある箇所があります。VB2022では ' があるとそこから行の最後までは注記とみなされ、何でも書くことができます。注記を入れることにより、プログラム作成日付、作成者などを記録することができる他、変数や配列の使用目的、プログラムの流れを記しておくことができるので、後から修正・改造を施すことになったとき作業が大変楽になります。
27行目から44行目を見てください。27行目の For と44行目の Next がペアで繰り返しブロックになっていますが、このブロックに囲まれた28~43行目はじの行も先頭に空白が何文字か入っています。このような行頭に空白を入れての字下げをインデントといいます。このようにブロック内の各行をインデントしておくとプログラムの構造がわかりやすくなります。
[プログラム詳細]
ということで、今回のサンプルプログラムは、注記を付けてプロックごとにインデントしてあるので、プログラムの流れについては特に詳細な説明がなくてもわかると思います。ここではこれ以外の点についてお話します。
このプログラムは小中学校・高校でクラス単位での使用を前提としています。1クラスの人数は50人まで対応しています。クラス内の出席番号は1から始まり、転校等でいなくなった児童(生徒)の番号はそのまま(学年の途中で出席番号の付け直しはしない)とします。
27~44行目のForブロックがstep1(受験者全員の点数をまとめて入力する)です。For~Nextは50回繰り返すことになっていますが、全員の点数を入力し終わったら50回繰り返してなくてもFor~Nextループを抜けるようにしています。
46~53行目はstep2です。受験者がひとりもいなかった場合、平均は計算できません(分母が0の割り算になってしまいます)。また秀(S)、補習対象者(F)が出ることもありませんから、受験者が0のときはこれらの計算は行なわないようになっています。
61~83行目はstep3です。step2で求めた平均、秀(S)ライン、補習対象者(F)ラインと、保存した各点数を比較するところです。このとき、受験者が0人だったときは、このstep3は実行されないようになっています。その仕掛けは変数saigoです。変数saigoはデータを保存した配列の最後の添え字 i の値を保持しています。もし受験者がひとりもいなければsaigoの値は0になります。そうすると61行目のFor制御文では開始値>終端値となり62~82行目は実行されません。
[昔はよかったなぁ]
昔のBASICにも配列はありました。昔のBASICでは