コンテンツにスキップ

配列とデータの一括処理

指導者向けの公開補足

学習本文に加えて、指導の視点・背景・授業での確かめ方を示します。どなたでも読めます。

指導の焦点

添字と要素の値を区別する。0始まりの添字なら、要素数と最後の添字は一つ違うことを、短い配列で確認する。

一歩踏み込んだ背景

配列の大きさや範囲外アクセスの扱いは言語によって違う。JavaScriptの挙動を、すべてのプログラミング言語の共通仕様として一般化しない。

授業での確かめ方

同じデータを個別の変数と配列で扱い、反復処理の違いを比べる。空配列や要素一つの場合も試し、平均などが計算できる条件を説明させる。

制度・規格等は本文末尾の参考資料も確認してください。

JSFiddleでコードを試す

JSFiddleは、ブラウザーでHTML・CSS・JavaScriptを入力して実行できるサービスです。短い動作確認から始められます。

  1. 新しい編集画面を開きます。JavaScriptは通常のJavaScriptを選び、外部ライブラリは追加しません。
  2. HTML欄にはページの本文、CSS欄には見た目、JavaScript欄には処理を書きます。HTML欄に<html>や<body>は不要です。JavaScript欄に<script>は付けません。
  3. DOMを使う例では、JavaScriptの実行タイミングを「On Load」「On DOM Ready」または「No wrap - bottom of body」にします。
  4. 「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の両方を載せた実習例は、この表示用コードで囲まず、それぞれの欄へ分けて貼り付けます。保存・共有時は公開範囲を確認し、個人情報やパスワードを入力しないでください。コードは手元にも残しましょう。

NAS・GitHub・CodePenなど、作業環境の選び方

この単元でできるようになること

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。合計には全要素を加え、最大値候補は今まで見た値より大きいときだけ更新する。最大値を最初の要素で初期化する方法は、すべて負の値であるデータにも応用できる。ただしこの方法は、配列が空でないことを前提にする。

空の配列の合計を零と定めることは自然でも、最大値を零と定めてよいとは限らない。「記録なし」と「最大が零」は意味が違う。平均も、空なら要素数が零なので割り算をそのまま行えない。処理の目的に応じて、記録なしを表示するなどの規則が必要だ。

存在しない添字を読むと、JavaScriptでは undefined になる場合がある。これを加算すれば数値として有効でない結果につながる。「エラーが出なかったので配列の範囲は正しかった」とは判断できない。反復の上限を length 以下ではなく、length 未満にする理由をここから説明できる。

全要素を一つずつ増やす
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 で宣言していても、配列の各要素は更新できる。名前へ別の配列を再代入することと、同じ配列の中身を変えることは異なる。ここでは反復中に長さを変えないため、各要素を一回ずつ更新できる。

配列の末尾へ追加する処理を、長さを条件にする反復の中で行うと、反復の終わりが先へ延びることがある。要素の値だけを変えるのか、追加や削除も行うのかを区別して設計しよう。順序を持つデータでは、削除で後ろの位置が変わることにも注意する。

棚が二段、各段に三つの区画があるなら、配列の中に配列を入れて表を表せる。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。各段の合計を零にする場所は、外側の反復の中、内側の反復の前である。零にする処理を両方の反復の外へ移すと、二段目の表示は二段目だけの合計ではなくなる。

配列を別の変数へ代入しても、要素を全部独立にコピーしたことにはならない。二つの名前で同じ配列を参照すれば、一方で変更した内容が他方からも見える。元の記録を残したいときは、必要な深さのコピーを作るか、元を変更しない処理を選ぶ。

参照と一段のコピーを区別する
const original = [6, 8];
const alias = original;
const copied = [...original];
alias[0] = 9;
console.log(original.join(","), copied.join(","));

出力は 9,8 6,8。展開構文で作った copied は、この数値だけの一次元配列では独立した配列になる。二次元配列の場合、外側をコピーするだけでは内側の配列を共有するので、同じ説明をそのまま適用できない。

注意: 配列の順序には意味がある。最大値を先頭へ移すなどの加工で、日付との対応を壊すことがある。集計のための並べ替えと、元記録の保存を分けて考えよう。

用語 意味
配列 要素を順序のあるまとまりとして扱う構造
添字 要素の位置を指定する番号
要素数 配列に並ぶ要素の個数
二次元配列 行と列など二つの添字で扱う配列の構造
参照 同じ対象を指して利用する関係
  1. 最初の配列の最後の要素を7に変えると、合計と最大値はいくつになるか。
  2. 棚の例で total の初期化を二つの反復の外へ移すと、二行の出力はどう変わるか。
  3. コピーの例で copied[1] = 0 を追加すると、original の二番目の値も変わるか。理由を説明しよう。
問1の解答例を見る

配列は[3,0,5,7]となり、合計は15、最大値は7になる。

問2の解答例を見る

出力は1 3と2 10になる。段の切替時に合計を0へ戻さなくなるので、二段目の7に一段目の3が累積される。

問3の解答例を見る

変わらない。copiedは展開構文で作った別の配列であり、この例の要素は数値なので、copiedの二番目を変えてもoriginalの二番目は8のままである。