【Javascript】 多次元配列 理解度チェック
この内容のテキストはこちら
問1 基本
[11, 22, 33]
と[100, 200, 300]
を配列の要素として入れ、300
を取得してください。
まずは要素として入れてみましょう。
let a = [[11, 22, 33], [100, 200, 300]];
次に、300
はどこにあるかというと、a[1][2]
ですね。よって、
let a = [[11, 22, 33], [100, 200, 300]]; let x = a[1][2]; // 300を取得
のようになります。
問2 for文
let x = [ [10, 11, 12], [20, 21, 22], ];
という変数を作成し、これのすべての値をfor文で出力してください。
配列が2次元なので、for文も2つ重ねます。外側のfor文で縦に、内側のfor文で横に走査します。
let x = [ [10, 11, 12], [20, 21, 22], ]; for (let i = 0; i < x.length; i++) { for (let j = 0; j < x[i].length; j++) { console.log(x[i][j]); } }
ここで、内側のfor文では、要素数を取得するのにx[i].length
としています。例えばx[0]
は[10, 11, 12]
なので、この長さを取得していることになりますね。
問3 配列から配列を作成
let x = [ [10, 11, 12], [20, 21, 22], ];
という配列から、奇数を取り除いた配列を作成してください。
まずは新たしい配列を作るための枠を用意しましょう。空の配列を置きます。
let even = [];
ここにfor文で追加していきましょう。ここで、各行ごとに空の配列を作って追加する必要があることに注意です。
let x = [ [10, 11, 12], [20, 21, 22], ]; let even = []; for (let i = 0; i < x.length; i++) { // 行ごとに空の配列を追加 even.push([]); for (let j = 0; j < x[i].length; j++) { // 奇数の場合だけpushする if (x[i][j] % 2 == 0) { // i行目の配列の最後尾に偶数を追加 even[i].push(x[i][j]); } } } console.log(even);
問4
難問です。無理に解く必要はありません。
例えば、次のような配列があったとします。
let x = [ [1, 3, 2, 9, 4], [3, 3, 1, 5, 9], [9, 1, 0, 0, 1], [6, 5, 5, 3, 6], ];
この中から、n * n (n >= 2)の大きさの要素を領域外にはみ出さないように取り出し、その平均を計算します。例えば3 * 3のサイズの場合
1 3 2 3 3 1 9 1 0
3 2 9 3 1 5 1 0 0
2 9 4 1 5 9 0 0 1
3 3 1 9 1 0 6 5 5
3 1 5 1 0 0 5 5 3
1 5 9 0 0 1 5 3 6
という要素が取り出せます。それぞれにある9つの値の平均をそれぞれ計算すると、この中で最も平均値が高いのは
3 3 1 9 1 0 6 5 5
で3.666…です。
このように、2次元配列を任意のn * n (n >=2) の範囲で切り出し、その平均値が最も高い領域を出力してください。
入出力例
let ary = [ [1, 3, 2, 9, 4], [3, 3, 1, 5, 9], [9, 1, 0, 0, 1], [6, 5, 5, 3, 6], ];
この場合は、下のように2 * 2で切り出した領域の平均が最も大きくなります。
9 4 5 9
let ary = [ [0, 0, 0, 0, 0], [0, 9, 9, 9, 0], [0, 9, 0, 9, 0], [0, 9, 9, 9, 0] ];
9 9 9 9 0 9 9 9 9
let ary = [ [1, 1, 2, 5, 9], [2, 8, 8, 7, 1], [1, 9, 2, 6, 1], [2, 9, 8, 8, 2] ];
8 8 7 9 2 6 9 8 8
これが解ければ、学生エンジニアなら十分な実力、社会人でも悪くないレベルです。atcoderなら茶色くらいの実力だと思います。
まずは、配列の左上を基準として平均値を出すことを考えてみます。y軸方向にsize
だけ、x軸方向にsize
だけfor文で回し、要素数で割ります。
// size * sizeの範囲の合計値を求める let sum = 0; for (let dy = 0; dy < size; dy++) { for (let dx = 0; dx < size; dx++) { sum += ary[dy][dx]; } } // 合計から平均を求める let avg = sum / (size * size);
次に、これをy軸とx軸で場所をずらすことを考えてみましょう。縦にy
, 横にx
だけずれるということは、配列の1次元目がy
、2次元目がx
増えるということです。
for (let dy = 0; dy < size; dy++) { for (let dx = 0; dx < size; dx++) { // yとxを足す = ずらす sum += ary[y + dy][x + dx]; } }
y
とx
は、囲む領域の左上の座標です。これをx, y軸ともに1ずつずらしていって、すべての領域を計算します。
// この2つのfor文は、合計値を求める際の左上のインデックス for (let y = 0; y < ary.length - size + 1; y++) { for (let x = 0; x < ary[y].length - size + 1; x++) { // size * sizeの範囲の合計値を求める let sum = 0; for (let dy = 0; dy < size; dy++) { for (let dx = 0; dx < size; dx++) { sum += ary[y + dy][x + dx]; } } // 合計から平均を求める let avg = sum / (size * size); } }
領域がはみ出さないようにfor文の条件を設定しておきましょう。
あとは、n * nの領域のサイズを変えていきます。正方形なので、サイズを変えるforは1つで良いですね。はみ出さないのが条件なので、最初の配列の縦か横の小さい方に最大サイズをあわせます。
let n = Math.min(ary.length, ary[0].length); for (let size = 2; size <= n; size++) { // この2つのfor文は、合計値を求める際の左上のインデックス for (let y = 0; y < ary.length - size + 1; y++) { for (let x = 0; x < ary[y].length - size + 1; x++) { // 略 } } }
これですべての領域で計算できるようになりました。残りは各領域の平均と、これまでの平均の最大値を比較し、更新していれば左上の座標と領域の大きさを記録します。
出力は、その記録をもとに行います。
let ary = [ [1, 1, 2, 5, 9], [2, 8, 8, 7, 1], [1, 9, 3, 6, 1], [2, 9, 8, 8, 2] ]; let n = Math.min(ary.length, ary[0].length); let maxAvg = 0; let maxX, maxY = 0; let maxSize = 0; for (let size = 2; size <= n; size++) { // この2つのfor文は、合計値を求める際の左上のインデックス for (let y = 0; y < ary.length - size + 1; y++) { for (let x = 0; x < ary[y].length - size + 1; x++) { // size * sizeの範囲の合計値を求める let sum = 0; for (let dy = 0; dy < size; dy++) { for (let dx = 0; dx < size; dx++) { sum += ary[y + dy][x + dx]; } } // 合計から平均を求める let avg = sum / (size * size); // 最も大きい平均値を更新 if (maxAvg < avg) { maxAvg = avg; maxX = x; maxY = y; maxSize = size; } } } } // 結果出力 let s = ""; for (let y = maxY; y < maxY + maxSize; y++) { for (let x = maxX; x < maxX + maxSize; x++) { s += ary[y][x] + " "; } s += "\n"; } console.log(s);
