【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) の範囲で切り出し、その平均値が最も高い領域を出力してください。

入出力例

入力1
let ary = [
    [1, 3, 2, 9, 4],
    [3, 3, 1, 5, 9],
    [9, 1, 0, 0, 1],
    [6, 5, 5, 3, 6],
];

この場合は、下のように2 * 2で切り出した領域の平均が最も大きくなります。

出力1
9 4 
5 9
入力2
let ary = [
    [0, 0, 0, 0, 0],
    [0, 9, 9, 9, 0],
    [0, 9, 0, 9, 0],
    [0, 9, 9, 9, 0]
];
出力2
9 9 9 
9 0 9
9 9 9
入力3
let ary = [
    [1, 1, 2, 5, 9],
    [2, 8, 8, 7, 1],
    [1, 9, 2, 6, 1],
    [2, 9, 8, 8, 2]
];
出力3
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];
    }
}

yxは、囲む領域の左上の座標です。これを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);
multidim thumb

役に立ったらシェアしよう!