擬似言語の合計・最大値・件数の求め方|科目Bで頻出の集計パターンを解説
合計や最大値を求めるコードは、なんとなく分かるのに自信が持てない。
繰返しの中で値がたまっていく処理を、最後まで追い切れていますか?
やっていることは足し算だけのはずなのに、選択肢を前にすると手が止まる。集計の問題について、そんな声をよく聞きます。
私はエンジニアとして10年以上、Webシステムの開発や運用に携わってきました。売上の集計処理で初期値を入れ忘れ、前日の数字が残ったまま加算されていた不具合を直したこともあります。
集計は、地味に見えて奥があります。この記事では、科目Bで繰り返し出てくる集計の形を、一つずつ分解して読めるようにしていきます。
集計はためる変数を用意することから始まる¶
まず、集計処理の骨組みを押さえましょう。どんな集計にも、結果をためておくための変数が必ず登場します。
合計なら合計をためる変数、件数なら数をためる変数です。この変数を、繰返しの外で用意しておくのが決まった形になります。
なぜ外なのか。中で用意してしまうと、繰返しのたびに中身がまっさらに戻ってしまうからです。
つまり集計処理は、三つの部分に分かれています。繰返しの前で準備し、繰返しの中で少しずつ更新し、繰返しの後で結果を使う。この三段構えが見えると、コードの形が急に読みやすくなります。
初期値の決め方で答えが変わる¶
準備の部分、つまり最初に何を入れておくかは、集計の種類によって変わります。ここを取り違えると、処理そのものは正しくても答えがずれます。
代表的な三つを並べて確認しましょう。
| 求めたいもの | ためる変数の初期値 | 繰返しの中でやること |
|---|---|---|
| 合計 | 0 | 要素の値を足す |
| 件数 | 0 | 条件に合えば1を足す |
| 最大値 | 先頭の要素の値 | 大きければ入れ替える |
合計と件数が0から始まるのは、感覚どおりだと思います。まだ何も足していない状態が0だからです。
問題は最大値です。ここだけ0ではなく、先頭の要素そのものを入れています。
その理由は、少し先で詳しく見ていきます。まずは、初期値が種類ごとに違うという事実だけ頭に置いてください。
配列の要素をひとつずつ見ていく形が土台になるので、添字の扱いに不安があれば先に確認しておくと理解が早くなります。
【関連記事】擬似言語の配列と添字がわからない人へ|要素数・二次元配列の読み方を解説
合計を求める基本の形¶
では、いちばん素直な合計から見ていきます。配列に入った数値を、先頭から順に足していく処理です。
○整数型の配列: data ← {40, 25, 70, 55}
○整数型: i, total
total ← 0 /* 繰返しの前で準備する */
i ← 1
while (i が data の要素数 以下)
total ← total + data[i] /* 今の要素を足しこむ */
i ← i + 1
endwhile
total を表示する /* 繰返しの後で結果を使う */
注目してほしいのは、total ← total + data[i] という行です。今の total に、今見ている要素を足して、また total に戻しています。
この書き方が、集計のいちばん基本の動きです。変数が自分自身を材料にして更新されていく形と言い換えてもいいでしょう。
言葉だけでは実感しにくいので、値の動きを表にします。
| 回数 | i | data[i] | 処理前の total | 処理後の total |
|---|---|---|---|---|
| 1回目 | 1 | 40 | 0 | 40 |
| 2回目 | 2 | 25 | 40 | 65 |
| 3回目 | 3 | 70 | 65 | 135 |
| 4回目 | 4 | 55 | 135 | 190 |
| 5回目 | 5 | ― | 190 | 条件が偽で終了 |
答えは190です。処理前と処理後を分けて書いておくと、どの時点の値を聞かれても答えられます。
こうした表を書く手順そのものに不安がある人は、専用の記事を用意しています。
【関連記事】擬似言語のトレース表の書き方|科目Bで変数の値を追う手順を解説
最大値を求める処理を読む¶
次は最大値です。合計との違いは、足すのではなく比べて入れ替えるところにあります。
配列の中でいちばん大きい値を探す処理を見てみましょう。
○整数型の配列: data ← {40, 25, 70, 55}
○整数型: i, max
max ← data[1] /* 先頭の値を仮の最大とする */
i ← 2 /* 2番目から比べ始める */
while (i が data の要素数 以下)
if (data[i] が max より大きい)
max ← data[i] /* 大きければ入れ替える */
endif
i ← i + 1
endwhile
max を表示する
やっていることは単純です。仮の最大を持ち歩き、それより大きい値に出会ったら持ち替える。
ここで、繰返しの開始が2番目になっている点にも気づいてください。先頭はすでに仮の最大として使っているので、もう一度比べる必要がないからです。
値の動きも追っておきましょう。
| 回数 | i | data[i] | max より大きいか | 処理後の max |
|---|---|---|---|---|
| 開始前 | ― | ― | ― | 40 |
| 1回目 | 2 | 25 | いいえ | 40 |
| 2回目 | 3 | 70 | はい | 70 |
| 3回目 | 4 | 55 | いいえ | 70 |
70が最大値でした。入れ替わったのは一度だけで、あとは素通りしています。
最初の要素を初期値にする理由¶
さて、先ほど保留にした話に戻ります。なぜ最大値だけ、初期値が0ではないのでしょうか。
答えは、負の数が混ざったときにあります。もし初期値を0にすると、すべての要素が負の数だった場合に、どれも0より大きくならず、0が答えとして残ってしまいます。
配列の中に存在しない値が答えになる。これは明らかにおかしいですよね。
先頭の要素を初期値にしておけば、答えは必ず配列の中のどれかになります。実務でも、この初期値の置き方は同じ理由で使われています。
最小値を求めるときも考え方は同じです。先頭を仮の最小として持ち、それより小さい値に出会ったら入れ替えます。
条件の向きが逆になるだけなので、if の中身を読み違えないよう注意してください。不等号の向きが読み取れれば、最大と最小はほぼ同じ処理です。
条件分岐の読み取りそのものを固めたい人は、こちらもあわせてどうぞ。
【関連記事】擬似言語のifで迷子になる人へ。擬似言語の条件分岐をスラスラ追う読み方
最大値の位置を聞かれることもある¶
出題では、最大値そのものではなく、それが何番目にあったかを問う形も見かけます。この場合は、値と一緒に位置も覚えておく必要があります。
入れ替えの行を二つにして、max ← data[i] の隣に ichi ← i を並べるだけです。値を持ち替えるタイミングと、位置を持ち替えるタイミングが同じである点が鍵になります。
片方だけ更新してしまうと、値と位置がちぐはぐになります。空欄補充で狙われやすいところなので、二つの行がセットになっているか確かめてください。
なお、この最大値を探す動きは、整列の処理にもそのまま出てきます。並べ替えの中で毎回いちばん大きい値を選び出す、という形です。
【関連記事】擬似言語の整列(ソート)がわからない人へ|選択ソートと交換処理の読み方を解説
条件に合うものだけ数える¶
三つ目は件数です。全部を数えるのではなく、ある条件を満たすものだけを数える形が主流になります。
繰返しの中に if を置き、条件に合ったときだけ1を足します。合計との違いは、足す値が要素そのものではなく1である点だけです。
50以上の要素がいくつあるかを数えてみましょう。
○整数型の配列: data ← {40, 25, 70, 55}
○整数型: i, kensu
kensu ← 0
i ← 1
while (i が data の要素数 以下)
if (data[i] が 50 以上)
kensu ← kensu + 1 /* 条件に合ったときだけ数える */
endif
i ← i + 1
endwhile
kensu を表示する
70と55が条件に合うので、答えは2です。if の中に入らなかった回は、kensu が変わらないまま次へ進みます。
ここまで来ると、集計の三つの形が同じ骨格でできていると分かってきたのではないでしょうか。準備して、繰返しの中で更新して、後で使う。違うのは初期値と更新の中身だけです。
繰返しの構造そのものが怪しいと感じたら、土台を固めておくと安心です。
【関連記事】擬似言語のwhileとforってどう違う?繰返し処理で迷子にならない方法を詳しく解説
平均を出すときは割る相手に注意¶
合計と件数がそろうと、平均を出す問題につながります。合計を件数で割るだけなので、計算そのものは簡単です。
気をつけたいのは、何で割るのかという点です。全体の要素数で割るのか、条件に合った件数で割るのかで、答えはまったく変わります。
条件に合ったものだけの平均を求めるなら、割る相手は条件に合った件数のほうです。問題文が何の平均を求めているのか、そこを先に読み取ってください。
もう一つ、件数が0になる可能性にも触れておきます。条件に合う要素が一つもなければ、0で割ることになってしまいます。
そのため、割る前に件数が0でないか確かめる分岐が入っている出題もあります。一見むだに見える if があったら、この用心である可能性が高いです。
科目Bでつまずきやすい場所¶
ここまでの形が分かっていても、本番で失点しやすい箇所は決まっています。私が学習の相談を受けてきた範囲では、次の三つが目立ちました。
先に知っておけば避けられるものばかりなので、表で確認しましょう。
| つまずく場所 | 何が起きるか | 対処 |
|---|---|---|
| 初期値の取り違え | 答えが一つ分ずれる、または0になる | 繰返しの前の行を必ず読む |
| 更新の位置が if の外 | 条件に関係なく数えてしまう | endif より前か後かを指差す |
| 集計の結果を中で使う | 途中経過が答えになる | 表示する行が繰返しの外か確かめる |
どれも知識としては簡単です。それでも、緊張した状態で急いで読むと、こういうところで足をすくわれます。
とくに二つ目は差がつきます。更新の行が if の内側にあるか外側にあるかで、処理の意味がまるごと変わってしまうからです。
空欄補充では初期値と更新の行を見る¶
集計の問題で空欄になりやすいのは、決まって初期値の行か更新の行です。この二つを重点的に見る、と決めておくだけで探す時間が減ります。
空欄が繰返しの前にあれば、初期値を問われています。合計や件数なら0、最大値なら先頭の要素、と当たりをつけられます。
空欄が繰返しの中にあれば、更新のしかたを問われています。足すのは要素そのものか、それとも1か。求めているものから逆算してください。
判断に迷ったら、要素が二つか三つだけの短い例を当てはめてみましょう。それだけで、選択肢のほとんどはふるい落とせます。
【関連記事】基本情報技術者試験の科目Bの空欄補充問題の解き方を解説|擬似言語で見る判断ポイント
見終わった後の値を答える¶
もう一つ、答え方でのつまずきにも触れておきます。集計の問題では、繰返しが終わった時点の値を聞かれるのが基本です。
途中の回の値を答えてしまう取り違えは、意外と多く起こります。表を書くときに、最後の行まで書き切ってから答えを選ぶようにしてください。
繰返しを抜けた直後の状態にしるしを付けておくと安全です。ここが答えだと目で分かる形にしておけば、選ぶときに迷いません。
手を動かして確かめるのが一番の近道¶
集計処理は、読むだけでは身につきにくい分野です。値が少しずつたまっていく感覚は、実際に追ってはじめて腑に落ちます。
まずは要素が四つほどの短い配列で、合計と最大値を紙に書いて追ってみてください。数分あれば終わりますし、一度やれば形が体に残ります。
そのうえで、コードを一行ずつ動かして確かめられるとさらに理解が速くなります。Giji Academy の擬似言語シミュレーターなら、変数の値が変わっていく様子を見ながら処理を追えます。
使い方から知りたい人は、次の記事に手順をまとめてあります。
【関連記事】擬似言語 シミュレーターとは?試験対策に役立つ使い方と学習法を解説
まとめ¶
最後に、この記事で確認したことを振り返ります。
集計処理は三段構えでできていました。繰返しの前で準備し、中で更新し、後で結果を使う。この骨組みが見えれば、どの集計も同じ形に見えてきます。
初期値は集計の種類で変わります。合計と件数は0から、最大値は先頭の要素から始めるのが基本でした。
最大値だけ先頭の要素を使うのは、負の数が混ざっても正しく求まるようにするためです。答えが必ず配列の中のどれかになる、という安心感があります。
件数を数える形は、合計の足す値が1に変わっただけのものでした。条件に合ったときだけ更新する、という点が合計との違いです。
そして最大のつまずきどころは、初期値と更新の行でした。空欄補充でもここが狙われるので、繰返しの前と中を意識して読む癖をつけてください。
集計が読めるようになると、科目Bで解ける問題は目に見えて増えます。今日の一問から、表を書いて追いかけてみましょう。