📘

PHP 多次元配列 練習問題 (ex02)

2023/04/25に公開

01

以下の要素を持った配列を宣言し、総和を求めなさい

1292 334 10 3044 302 028 948 8190 9492 982 02038 9803 34234 32420 827 928
答えと解説

答え

104872

ソースコード

<h1> forを使う場合 </h1>
<?php
// 
$ary = [ 1292, 334, 10, 3044, 302, 28,948, 8190, 9492, 982, 2038, 9803, 34234, 32420, 827, 928 ];

$sum = 0;
for($i = 0; $i < count($ary); $i++){
    $sum += $ary[$i];
}
echo $sum;
?>

<h1> foreachを使う場合 </h1>
<?php
$ary = [ 1292, 334, 10, 3044, 302, 28,948, 8190, 9492, 982, 2038, 9803, 34234, 32420, 827, 928 ];

$sum = 0;
foreach($ary as $element){
    $sum += $element;
}
echo $sum;
?>

頭文字に0がついている028等の数字については28のように0を取る。

forを使うか、foreachを使うかは書き手次第。
forを使う場合にはカウンタ$iを使うことと、配列の要素数を取得するcount()メソッドを使用するとシンプルに記述できる。

$sum += $ary[$i]$sum = $sum + $ary[$i]と同じ計算が可能な記述方法。
少し短く描ける。

02

下記に学生のテストの得点を示す。次の問に答えよ
ただし、配列は示したものを使用するものとする

科目名 A君 B君 C君 D君 E君 F君 G君 H君
数学 59 63 95 32 100 33 92 63
国語 82 49 11 50 38 12 30 50
理科 39 20 29 30 30 91 89 65
入力
<?php
$data = [
    [ 59, 63, 95, 32, 100, 33, 92, 63],
    [ 82, 49, 11, 50, 38, 12, 30, 50], 
    [ 39, 20, 29, 30, 30, 91, 89, 65],
];

02-1 各科目の平均点を算出せよ

出力例(数字はデタラメ):

数学: 100点
国語: 100点
理科: 100点

02-2 個人の総得点を算出せよ

出力例(数字はデタラメ):

A君: 100点
B君: 100点
C君: 100点
D君: 100点
E君: 100点
F君: 100点
G君: 100点
H君: 100点
答えと解説
  1. データの読み込み
<h1> データの読み込み </h1>
<?php
$data = [
    [ 59, 63, 95, 32, 100, 33, 92, 63],
    [ 82, 49, 11, 50, 38, 12, 30, 50], 
    [ 39, 20, 29, 30, 30, 91, 89, 65],
];

foreach($data as $row){
    foreach($row as $element){
        // PHPの文字列連結は"."であることに注意
        echo $element . " ";
    }
    echo "<br>";
}
?>

foreachを入れ子にして使うことで、二次元配列の表示も可能になる。

外側のループで要素として取り出した項目を内側のループでは配列として扱うのがポイント

  1. 計算部分

個人の計算をしようと思うと、A君の総得点、B君の総得点、C君の... のように表を縦に見て計算を進めていくことが想像できる。

以下がその実装

// A~Hくんの得点をまとめて初期化
$sum = [0,0,0,0,0,0,0,0];
// 縦に見ていく方法
for($i = 0; $i < count($sum); $i++){
    for($j = 0; $j < count($data); $j++){
        $sum[$i] += $data[$j][$i];
    }
}

外側のループ上限は学生の人数とし、内側のループ上限は科目の数とする。

あとは該当する学生の得点の配列に加算してあげればいい。

このとき、$dataの要素には

$data["科目の要素番号"]["学生の要素番号"]

でアクセスすることに注意。

例:
B君(インデックスは1)の理科(インデックスは2)の得点を取得したいときは

$data[2][1]

となる


ただし、表は縦に見るほかに横に見ることもできる

以下がその実装

// A~Hくんの得点をまとめて初期化
$sum = [0,0,0,0,0,0,0,0];

// 横に見ていく方法
for($i = 0; $i < count($data); $i++){
    for($j = 0; $j < count($data[$i]); $j++){
        $sum[$j] += $data[$i][$j];
    }
}

こちらは$dataで参照しているカウンタ変数($i$j)が入れ替わってることに注意


この2つの場合、理想的なのは後者の実装になる。
細かい説明は省くが、配列は基本的に小さい次元からループ処理した方が、メモリアクセスの効率化が見込める。

  1. 表示
<h3> A君: <?php echo $sum[0] ?></h3>
<h3> B君: <?php echo $sum[1] ?></h3>
<h3> C君: <?php echo $sum[2] ?></h3>
<h3> D君: <?php echo $sum[3] ?></h3>
<h3> E君: <?php echo $sum[4] ?></h3>
<h3> F君: <?php echo $sum[5] ?></h3>
<h3> G君: <?php echo $sum[6] ?></h3>
<h3> H君: <?php echo $sum[7] ?></h3>

$sumに適切に値が代入されていれば表示される

  1. 答え
A君: 180
B君: 132
C君: 135
D君: 112
E君: 168
F君: 136
G君: 211
H君: 178

03

以下の400マスを掛け算で計算をせよ

入力:

<?php
$input = [
    [0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19,20],
    [18,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [12,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [3,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [5,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [8,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [7,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [11,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [6,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [9,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [4,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [13,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [10,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [19,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [2,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [14,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [16,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [17,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [15,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [20,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
答えと解説
<h1> データの入力 </h1>
<?php
$input = [
    [0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19,20],
    [18,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [12,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [3,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [5,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [8,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [7,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [11,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [6,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [9,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [4,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [13,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [10,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [19,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [2,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [14,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [16,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [17,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [15,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [20,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];

foreach($input as $row){
    foreach($row as $element){
        echo $element . " ";
    }
    echo "<br>";
}
?>

<?php

for($i = 1; $i < count($input) ; $i++){
    for($j = 1; $j < count($input[$i]); $j++){
        $input[$i][$j] = $input[0][$j] * $input[$i][0];
    }
}

?>


<h1> 結果 </h1>

<?php
foreach($input as $row){
    foreach($row as $element){
        // echo $element . " ";
        echo sprintf('%03d', $element) . " ";
    }
    echo "<br>";
}
?>

縦の要素と横の要素の0個目は計算の右辺と左辺になるのでループからは除外し、計算の時のみ使ってあげるとシンプル

sprintf関数は0埋めするために使用(そろってたほうが見やすい)

答え

img

04

以下のような2次元配列がある時、次の問いに答えよ

[
  [4, 3, -1],
  [30, 4, 2],
  [1, 1, 19]
]

04-1

この配列の行数、列数を求めよ

04-2

この配列の各行の合計値を求め、結果を1次元配列として表示せよ。

04-3

この配列の各列の合計値を求め、結果を1次元配列として表示せよ。

04-4

この配列の対角線上の要素の合計値を求めよ。

答えと解説
  1. データの読み込み
<h1> データの入力 </h1>

<?php
$data = [
    [4, 3, -1],
    [30, 4, 2],
    [1, 1, 19]
];

foreach($data as $row){
    foreach($row as $element){
        echo $element . ", ";
    }
    echo "<br>";
}
?>
  1. 04-1
<?php
echo "行データ: ". count($data);
echo "<br>";
echo "列データ: ". count($data[0]);

?>

PHPの場合はcountメソッドを使うと便利。

今回は行列であるため、1行目から最後の行、1列目から最後の列までデータの数が変わらないため、
列数を求めるときは1行目のデータを使う。

列のデータ数が行によって異なる場合は行を読み込む度に、求める必要が出てくる。

  1. 04-2
<h2> 04-2</h2>

<?php

$sums = [];
for( $i = 0; $i < count($data); $i++){
    for($j = 0; $j < count($data[$i]); $j++){
        $sums[$i] += $data[$i][$j];
    }
    // echo $sums[$i]. "<br>";
}
?>
<div>中身だけ表示</div>
<?php
echo "[ ";
foreach($sums as $sum){
     echo $sum. " ";
}
echo "] <br>";

?>

<div>カンマ区切りで表示</div>
<?php
echo "[ ";
foreach($sums as $sum){
     echo $sum;
     if ($sum !== end($sums)){
        echo ", ";
     } 
}
echo "] <br>";
?>

中身だけ出力する場合には前者の実装でよい。

もし、カンマ区切りで表示したい場合、最後の要素の後はカンマを表示しないようにする必要がある。

foreachの最後の要素はendを使用すると求められるので最後の要素でなければカンマを記述するように分岐をする。

endに類する関数がなければ、countメソッドとカウンタを使うことで実現できる

echo "[ ";
for($i = 0; $i < count($sums); $i++){
    echo $sums[$i];
    if ($i < count($sums) - 1){
        echo ", ";
    } 
}
echo "] <br>";

その場合、最後の要素のインデックスは<要素数> - 1であることに注意

  1. 04-3
<h2> 04-3</h2>

<?php
$sums = [0, 0, 0]; // 0で初期化
for($i = 0 ; $i < count($data); $i++){
    for($j = 0 ; $j <  count($data[$i]); $j++){
        $sums[$j] +=  $data[$i][$j];
    }
}

echo "[ ";
foreach($sums as $sum){
    echo $sum;
    if ($sum !== end($sums)){
        echo ", ";
    } 
}
echo "] <br>";

?>
  1. 04-4
<h2> 04-4</h2>
<?php

$sum = 0;
for($i = 0 ; $i < count($data); $i++){
    $sum +=  $data[$i][$i];
}

echo $sum;

?>

答え
img

05

以下のような3次元配列がある時、各要素を1つずつ取り出して、例の形で出力しなさい。

[
  [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
  ],
  [
    [10, 11, 12],
    [13, 14, 15],
    [16, 17, 18]
  ]
]

出力例:

Element 1: 1
Element 2: 2
Element 3: 3
Element 4: 4
Element 5: 5
Element 6: 6
Element 7: 7
Element 8: 8
Element 9: 9
Element 10: 10
Element 11: 11
Element 12: 12
Element 13: 13
Element 14: 14
Element 15: 15
Element 16: 16
Element 17: 17
Element 18: 18
答えと解説
$input = [
    [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]
    ],
    [
        [10, 11, 12],
        [13, 14, 15],
        [16, 17, 18]
    ]
];

$counter = 1;
foreach($input as $matrix){
    foreach($matrix as $col){
        foreach($col as $datum){
            echo "Element ". $counter .":" . $datum. "<br>";
            $counter++;
        }
    }
}

ループが3重になることに気づけば問題なく解ける

上記の例ではforeachを使用しているが、for文を使っても可能

foreachの場合、全体の要素数をカウントするためのカウンタが必要になってくることに注意

答えは出力例と同じ結果

06

以下の二次元配列が与えられる時、この配列を転置した配列を求めよ

[
  [2, 3, 1],
  [5, 4, 2],
  [1, 1, 7]
]
転置とは

転置とは、行と列を入れ替えることを指す。つまり、上記の配列を転置すると、以下のような配列が得られる。

[
  [2, 5, 1],
  [3, 4, 1],
  [1, 2, 7]
]
答えと解説

<h1>データの入力</h1>
<?php
$matrix =  [
    [2, 5, 1],
    [3, 4, 1],
    [1, 2, 7]
];
// 入力データの表示
foreach($matrix as $row){
    foreach($row as $element){
        echo $element . " ";
    }
    echo "<br>";
}
?>

<h1>処理</h1>
<?php

// 初期化
$transpose = [
    [0, 0, 0],
    [0, 0, 0],
    [0, 0, 0]
];
for($i = 0 ; $i < count($matrix); $i++){
    for($j = 0 ; $j < count($matrix[$i]) ; $j++){
        $transpose[$i][$j] = $matrix [$j][$i];
    }
}
// 結果の表示
foreach($transpose as $row){
    foreach($row as $element){
        echo $element . " ";
    }
    echo "<br>";
}

?>

要素のアクセス時に行と列のインデックスを逆にしてあげれば良い

最終的に「転置とは」にある配列と同じ出力ができていればOK

例では別の変数に格納までを行なっている。

移行する行列($transpose)の初期化はPHPの場合必要ないが、別の言語だと必要になったりするので少し注意してもいいかもしれない。

Discussion