Prompt

ある2次元配列”matrix”のデータを縦横”scale”倍に拡大コピーした状態で、それを1次元配列”array”に収まるように格納する。
“matrix”のデータ1つは”array”の4領域分を必要とし、それぞれの領域には変数”a”, “b”, “c”, “d”の値を代入するとする。
“array”の要素数はmatrix.length * scale * matrix[0].length * scale * 4となる。

インデックスアクセスが超絶複雑になって分からなくなったから、やり方を教えて!

おいっす!👍 プログラミングでインデックスの計算が複雑になると、頭がこんがらがっちゃうよね。大丈夫、一緒に整理していこう!

君がやろうとしているのは、2次元配列を拡大して1次元配列に格納する処理だね。この種のインデックス変換は、座標変換の考え方を使うとスッキリするよ。

1. 座標の対応関係を考える

まず、元の2次元配列 matrix と、最終的な1次元配列 array のインデックスの関係をマッピングしよう。

  • 元の2次元配列 matrix のインデックス:

    • row: 行インデックス
    • col: 列インデックス
  • 拡大後の仮想的な2次元グリッドのインデックス:

    • bigRow: 拡大後のグリッドの行インデックス
    • bigCol: 拡大後のグリッドの列インデックス
  • 最終的な1次元配列 array のインデックス:

    • arrayIndex: 1次元配列のインデックス

2. インデックスの計算式

この3つのインデックスの関係は、以下の式で表せる。

a. (bigRow, bigCol)から(row, col)への変換

拡大コピーだから、元の matrix のどの要素に対応するかは、割り算で簡単にわかる。

例えば、scaleが3のとき、bigRowが0, 1, 2のときはrowが0に、3, 4, 5のときはrowが1になる、ってことだ。

b. (bigRow, bigCol)からarrayIndexへの変換

ここが一番複雑なところだね。1つのmatrixの要素がarrayの4つの領域(a, b, c, d)に対応するから、その分も考慮する必要がある。

ここで、offseta, b, c, dのどの領域にアクセスするかによって変わる。

  • aにアクセス: offset = 0
  • bにアクセス: offset = 1
  • cにアクセス: offset = 2
  • dにアクセス: offset = 3

3. 具体的なコードに落とし込む

この計算式をforループに適用してみよう。

const matrix = [[1, 2], [3, 4]];
const scale = 2;
const matrixWidth = matrix[0].length;
const matrixHeight = matrix.length;
 
// 最終的な1次元配列のサイズを計算
const arraySize = matrixHeight * scale * matrixWidth * scale * 4;
const array = new Array(arraySize);
 
// 拡大後のグリッドのサイズ
const bigWidth = matrixWidth * scale;
const bigHeight = matrixHeight * scale;
 
// ループを回す
for (let bigRow = 0; bigRow < bigHeight; bigRow++) {
  for (let bigCol = 0; bigCol < bigWidth; bigCol++) {
    // 拡大グリッドのインデックスから、元のmatrixのインデックスを計算
    const row = Math.floor(bigRow / scale);
    const col = Math.floor(bigCol / scale);
 
    // 元のデータを取り出す
    const value = matrix[row][col];
 
    // 1次元配列のインデックスを計算
    const arrayBaseIndex = (bigRow * bigWidth + bigCol) * 4;
 
    // 4つの領域に値を格納
    array[arrayBaseIndex] = value;         // a
    array[arrayBaseIndex + 1] = value + 1; // b (例として1を足す)
    array[arrayBaseIndex + 2] = value + 2; // c (例として2を足す)
    array[arrayBaseIndex + 3] = value + 3; // d (例として3を足す)
  }
}
 
console.log(array);
// 出力例: [1, 2, 3, 4, 1, 2, 3, 4, 2, 3, 4, 5, 2, 3, 4, 5, ...]

この方法なら、複雑なインデックス計算を2段階に分けて考えることができるから、グッとシンプルになるはず。1次元配列のインデックス計算でよくある**行インデックス * 幅 + 列インデックス**のパターンも使ってるから、見慣れているかもしれないね。

この考え方を使えば、もうインデックスで迷うことはないはず!頑張ってくれ!🚀