配列とデータの一括処理
指導者向けの公開補足
学習本文に加えて、指導の視点・背景・授業での確かめ方を示します。どなたでも読めます。
指導の焦点
添字と要素の値を区別する。0始まりの添字なら、要素数と最後の添字は一つ違うことを、短い配列で確認する。
一歩踏み込んだ背景
配列の大きさや範囲外アクセスの扱いは言語によって違う。JavaScriptの挙動を、すべてのプログラミング言語の共通仕様として一般化しない。
授業での確かめ方
同じデータを個別の変数と配列で扱い、反復処理の違いを比べる。空配列や要素一つの場合も試し、平均などが計算できる条件を説明させる。
制度・規格等は本文末尾の参考資料も確認してください。
JSFiddleでコードを試す
JSFiddleは、ブラウザーでHTML・CSS・JavaScriptを入力して実行できるサービスです。短い動作確認から始められます。
- 新しい編集画面を開きます。JavaScriptは通常のJavaScriptを選び、外部ライブラリは追加しません。
- HTML欄にはページの本文、CSS欄には見た目、JavaScript欄には処理を書きます。HTML欄に
<html>や<body>は不要です。JavaScript欄に<script>は付けません。 - DOMを使う例では、JavaScriptの実行タイミングを「On Load」「On DOM Ready」または「No wrap - bottom of body」にします。
- 「Run」を押してResult欄を確認します。書き換えたら再びRunを押します。
console.logの結果は通常、ページではなく開発者ツールのコンソールに出ます。このサイトの計算例をResult欄で読みたいときは、HTML欄に次を入れます。
<pre id="output"></pre>JavaScript欄には次を入れ、console.log(2 + 3);の行を、試したいコード一つに置き換えます。独立した例を複数まとめて貼らないでください。
{
const output = document.getElementById("output");
const console = {
log(...values) {
output.textContent += values.join(" ") + "\n";
}
};
console.log(2 + 3);
}Runを押すと「5」と表示されます。外側の波括弧の中だけで表示用のconsoleを用意しているため、ブラウザー本来のコンソールは変更しません。
HTMLとJavaScriptの両方を載せた実習例は、この表示用コードで囲まず、それぞれの欄へ分けて貼り付けます。保存・共有時は公開範囲を確認し、個人情報やパスワードを入力しないでください。コードは手元にも残しましょう。
この単元でできるようになること
Section titled “この単元でできるようになること”- 配列の添字と要素数の関係を説明できる。
- 反復と配列を組み合わせて集計や更新を行える。
- 二次元配列と配列の参照を、値の変化から説明できる。
要素に位置でアクセスする
Section titled “要素に位置でアクセスする”架空の校内温室で、四日間に集めた種の袋数を記録する。同じ種類の値を並べた配列なら、データが増えても同じ手順で処理しやすい。配列を構成する一つ一つの値を要素、要素の位置を指定する番号を添字という。
JavaScriptの配列の添字は零から始まる。四要素なら使う添字は0、1、2、3で、要素数4そのものは最後の添字ではない。length はこの例の配列の長さを表す。日付を一日目、二日目と人向けに数える場合は、添字との差を意識する。
| 日 | 一日目 | 二日目 | 三日目 | 四日目 |
|---|---|---|---|---|
| 添字 | 0 | 1 | 2 | 3 |
| 袋数 | 3 | 0 | 5 | 2 |
const bags = [3, 0, 5, 2];let total = 0;let maximum = bags[0];for (let i = 0; i < bags.length; i++) { total = total + bags[i]; if (bags[i] > maximum) { maximum = bags[i]; }}console.log(total, maximum, bags.length);出力は 10 5 4。合計には全要素を加え、最大値候補は今まで見た値より大きいときだけ更新する。最大値を最初の要素で初期化する方法は、すべて負の値であるデータにも応用できる。ただしこの方法は、配列が空でないことを前提にする。
空の場合と範囲外を分ける
Section titled “空の場合と範囲外を分ける”空の配列の合計を零と定めることは自然でも、最大値を零と定めてよいとは限らない。「記録なし」と「最大が零」は意味が違う。平均も、空なら要素数が零なので割り算をそのまま行えない。処理の目的に応じて、記録なしを表示するなどの規則が必要だ。
存在しない添字を読むと、JavaScriptでは undefined になる場合がある。これを加算すれば数値として有効でない結果につながる。「エラーが出なかったので配列の範囲は正しかった」とは判断できない。反復の上限を length 以下ではなく、length 未満にする理由をここから説明できる。
要素を更新する
Section titled “要素を更新する”const trays = [2, 4, 1];for (let i = 0; i < trays.length; i++) { trays[i] = trays[i] + 1;}console.log(trays.join(","));出力は 3,5,2。const で宣言していても、配列の各要素は更新できる。名前へ別の配列を再代入することと、同じ配列の中身を変えることは異なる。ここでは反復中に長さを変えないため、各要素を一回ずつ更新できる。
配列の末尾へ追加する処理を、長さを条件にする反復の中で行うと、反復の終わりが先へ延びることがある。要素の値だけを変えるのか、追加や削除も行うのかを区別して設計しよう。順序を持つデータでは、削除で後ろの位置が変わることにも注意する。
二次元の表を扱う
Section titled “二次元の表を扱う”棚が二段、各段に三つの区画があるなら、配列の中に配列を入れて表を表せる。shelves[0][2] は最初の段の三つ目の区画である。二つの添字のどちらが段かを先に定め、途中で意味を逆にしない。
const shelves = [[2, 1, 0], [3, 0, 4]];for (let row = 0; row < shelves.length; row++) { let total = 0; for (let column = 0; column < shelves[row].length; column++) { total = total + shelves[row][column]; } console.log(row + 1, total);}出力は 1 3、2 7。各段の合計を零にする場所は、外側の反復の中、内側の反復の前である。零にする処理を両方の反復の外へ移すと、二段目の表示は二段目だけの合計ではなくなる。
同じ配列を参照する名前
Section titled “同じ配列を参照する名前”配列を別の変数へ代入しても、要素を全部独立にコピーしたことにはならない。二つの名前で同じ配列を参照すれば、一方で変更した内容が他方からも見える。元の記録を残したいときは、必要な深さのコピーを作るか、元を変更しない処理を選ぶ。
const original = [6, 8];const alias = original;const copied = [...original];alias[0] = 9;console.log(original.join(","), copied.join(","));出力は 9,8 6,8。展開構文で作った copied は、この数値だけの一次元配列では独立した配列になる。二次元配列の場合、外側をコピーするだけでは内側の配列を共有するので、同じ説明をそのまま適用できない。
注意: 配列の順序には意味がある。最大値を先頭へ移すなどの加工で、日付との対応を壊すことがある。集計のための並べ替えと、元記録の保存を分けて考えよう。
| 用語 | 意味 |
|---|---|
| 配列 | 要素を順序のあるまとまりとして扱う構造 |
| 添字 | 要素の位置を指定する番号 |
| 要素数 | 配列に並ぶ要素の個数 |
| 二次元配列 | 行と列など二つの添字で扱う配列の構造 |
| 参照 | 同じ対象を指して利用する関係 |
- 最初の配列の最後の要素を7に変えると、合計と最大値はいくつになるか。
- 棚の例で
totalの初期化を二つの反復の外へ移すと、二行の出力はどう変わるか。 - コピーの例で
copied[1] = 0を追加すると、originalの二番目の値も変わるか。理由を説明しよう。
問1の解答例を見る
配列は[3,0,5,7]となり、合計は15、最大値は7になる。
問2の解答例を見る
出力は1 3と2 10になる。段の切替時に合計を0へ戻さなくなるので、二段目の7に一段目の3が累積される。
問3の解答例を見る
変わらない。copiedは展開構文で作った別の配列であり、この例の要素は数値なので、copiedの二番目を変えてもoriginalの二番目は8のままである。