PHP 多次元配列 練習問題 (ex02)
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点
答えと解説
- データの読み込み
<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を入れ子にして使うことで、二次元配列の表示も可能になる。
外側のループで要素として取り出した項目を内側のループでは配列として扱うのがポイント
- 計算部分
個人の計算をしようと思うと、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つの場合、理想的なのは後者の実装になる。
細かい説明は省くが、配列は基本的に小さい次元からループ処理した方が、メモリアクセスの効率化が見込める。
- 表示
<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
に適切に値が代入されていれば表示される
- 答え
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埋めするために使用(そろってたほうが見やすい)
答え
04
以下のような2次元配列がある時、次の問いに答えよ
[
[4, 3, -1],
[30, 4, 2],
[1, 1, 19]
]
04-1
この配列の行数、列数を求めよ
04-2
この配列の各行の合計値を求め、結果を1次元配列として表示せよ。
04-3
この配列の各列の合計値を求め、結果を1次元配列として表示せよ。
04-4
この配列の対角線上の要素の合計値を求めよ。
答えと解説
- データの読み込み
<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>";
}
?>
- 04-1
<?php
echo "行データ: ". count($data);
echo "<br>";
echo "列データ: ". count($data[0]);
?>
PHPの場合はcount
メソッドを使うと便利。
今回は行列であるため、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
であることに注意
- 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>";
?>
- 04-4
<h2> 04-4</h2>
<?php
$sum = 0;
for($i = 0 ; $i < count($data); $i++){
$sum += $data[$i][$i];
}
echo $sum;
?>
答え
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