質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

4回答

2990閲覧

PHP 多次元配列 for文

n_k23

総合スコア21

多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

1クリップ

投稿2021/11/02 07:40

編集2021/11/02 09:26

前提・解決したいこと

PHPで配列の中身をfor文を使用して表を作りたい。
しかし、多次元連想配列のfor文の出力出力の仕方が思いつかず、躓いています。
(表示はHTMLの<table>タグを使用します。)

発生している問題

多次元連想配列でのfor文の出力方法。
配列データの計算方法。

PHP

1<?php 2/** 3 * 表示イメージ 4 * _________________________ 5 * |_____|_c1|_c2|_c3|横合計| 6 * |___r1|_10|__5|_20|___35| 7 * |___r2|__7|__8|_12|___27| 8 * |___r3|_25|__9|130|__164| 9 * |縦合計|_42|_22|162|__226| 10 * ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ 11*/ 12 13$arr = [ 14 'r1' => ['c1' => 10, 'c2' => 5, 'c3' => 20], 15 'r2' => ['c1' => 7, 'c2' => 8, 'c3' => 12], 16 'r3' => ['c1' => 25, 'c2' => 9, 'c3' => 130] 17]; 18?> 19 20<body> 21 <!-- ここにテーブル表示 --> 22 23</body> 24<style> 25table { 26 border:1px solid #000; 27 border-collapse: collapse; 28} 29th, td { 30 border:1px solid #000; 31} 32</style>

他のQ&A等を検索してみてもよく分からず
質問させて頂きます。
申し訳ありませんがよろしくお願いします。

###試したこと

PHP

1//一つずつターミナル上で確認してみた 2$arr = [ 3 'r1' => ['c1' => 10, 'c2' => 5, 'c3' => 20], 4 'r2' => ['c1' => 7, 'c2' => 8, 'c3' => 12], 5 'r3' => ['c1' => 25, 'c2' => 9, 'c3' => 130] 6]; 7 8//配列の確認 9print_r($arr); 10//配列の出力 11echo $arr['r3']['c2']; 12//配列の計算 うまくいかず 13$sum = array_sum(array_column($arr,['r1'].['c2'])); 14echo $sum; 15<?php 16 17?>

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tanat

2021/11/02 08:06

上手くいっていないソースで良いので、書いたところ、理解しているところまでを質問に追記してみて下さい。 例えば、tableが絡まなければ多次元配列の展開自体は出来るのか、それ自体もよくわからないかなど。 現在の質問だと、何が分からないのかが第三者からは把握出来ません。
n_k23

2021/11/02 08:45

質問への追記・修正の依頼誠にありがとうございます。 内容については後ほど追記・修正させて頂きます。 多次元配列の展開もよく分からない状況です。
cerfweb

2021/11/02 09:00

foreachではなくてどうしてもforを使わないといけないのでしょうか。
n_k23

2021/11/02 09:06

cerfweb様 foreachではなくfor文を使用して表示するよう言われています。
tanat

2021/11/02 09:33

追記ありがとうございます。 1次元配列をforで展開する事はできますか?
n_k23

2021/11/02 09:37

tanat様 1次元配列でのfor文展開はできます。
guest

回答4

0

いろいろなやり方があると思いますが、カラム数がわかっているという前提なら以下のようにも展開できます。

php

1<?php 2$c = []; // 最終行の合計を入れる配列 3$cnt = count($arr); 4?> 5<table> 6 <thead> 7 <tr> 8 <th></th> 9 <th>c1</th> 10 <th>c2</th> 11 <th>c3</th> 12 <th>横合計</th> 13 </tr> 14 </thead> 15 <tbody> 16 <?php for ($i = 1; $i <= $cnt; $i ++): ?> 17 <tr> 18 <td>r<?php echo $i; ?></td> 19 <?php $sub_total = 0; for ($j = 1; $j <= 3; $j ++): ?> 20 <td><?php $n = $arr['r' . $i]['c' . $j]; echo $n; ?></td> 21 <?php $c[$j] = isset($c[$j]) ? $c[$j] + $n : $n; $sub_total += $n; endfor; ?> 22 <td><?php echo $sub_total; ?></td> 23 </tr> 24 <?php endfor; ?> 25 </tbody> 26 <tfoot> 27 <tr> 28 <th>縦合計</th> 29 <?php for ($i = 1; $i <= 3; $i ++): ?> 30 <th><?php echo $c[$i]; ?></th> 31 <?php endfor; ?> 32 <th><?php echo array_sum($c); ?></th> 33 </tr> 34 </tfoot> 35</table>

投稿2021/11/02 09:54

cerfweb

総合スコア1907

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

n_k23

2021/11/02 10:38

cerfweb様 回答誠にありがとうございます。 回答内容を自分で精査しながら復習をしていきます。 この方法についての参考になる解説、資料、URL等が ありましたら教えてもらえないでしょうか?
n_k23

2021/11/02 15:09

cerfweb様 返信ありがとうございます。 php.netで確認してみます。
guest

0

ベストアンサー

おはようございます、天使です。
これが、前述コードの発展形です。

コーディング・ポリシー

前述のコードをMVCデザインパターンを意識したオブジェクト指向で表現しました。
PHP 7 の新機能を含んでいるため、PHP 5 系では修正が必要です。

設計

このコードでは、logic と view を完全に分離しました。
index.php がメイン処理(Controller相当)
Table.php が表の部品を管理するクラス(Model相当〈バリデーター内封型〉)
View.php が描画を行う静的クラス(View相当)
となっています。

PHP

1// index.php 2<?php 3include "./Table.php"; 4include "./View.php"; 5 6// 入力 7$arr = [ 8 'r1' => ['c1' => 10, 'c2' => 5, 'c3' => 20], 9 'r2' => ['c1' => 7, 'c2' => 8, 'c3' => 12], 10 'r3' => ['c1' => 25, 'c2' => 9, 'c3' => 130] 11]; 12 13try 14{ 15 // Tableオブジェクトの初期化 16 $table = new teratail\angel_sun\Table($arr); 17 18 // テーブル描画 19 teratail\angel_sun\View::render($table); 20} 21catch(\Throwable $th) 22{ 23 teratail\angel_sun\View::on_error($th); 24}

PHP

1// View.php 2<?php 3 4declare(strict_types=1); 5 6namespace teratail\angel_sun; 7 8class View 9{ 10 public static function render(Table $obj): void 11 { 12 echo <<< EOL 13<html lang="ja"> 14 <head> 15 <meta charset="utf-8"> 16 <title>表計算</title> 17 <style> 18table { 19 border:1px solid #000; 20 border-collapse: collapse; 21} 22th, td { 23 border:1px solid #000; 24 text-align: right; 25 padding: 4px 6px; 26} 27 </style> 28 </head> 29 <body> 30 <table> 31 <thead> 32 <tr> 33 {$obj->get_header()} 34 </tr> 35 </thead> 36 <tbody> 37 {$obj->get_body()} 38 </tbody> 39 <tfoot> 40 <tr> 41 {$obj->get_footer()} 42 </tr> 43 </tfoot> 44 </table> 45 </body> 46</html> 47EOL; 48 } 49 50 public static function on_error(\Throwable $th): void 51 { 52 $nl2br = function($message){ return nl2br($message); }; 53 54 echo <<< EOL 55<html lang="ja"> 56 <head> 57 <meta charset="utf-8"> 58 <title>入力エラー:表計算</title> 59 </head> 60 <body> 61 <h1>入力エラー</h1> 62 <h4>{$th->getMessage()}</h4> 63 <p>{$nl2br($th->getTraceAsString())}</p> 64 </body> 65</html> 66EOL; 67 } 68}

PHP

1// Table.php 2<?php 3 4declare(strict_types=1); 5 6namespace teratail\angel_sun; 7 8class Table 9{ 10 private $arr; 11 private $row_keys; // 行インデックスのリスト 例)["r1", "r2", "r3"] 12 private $col_keys; // 列インデックスのリスト 例)["c1", "c2", "c3]; 13 private $rows; // 行数 14 private $cols; // 列数 15 private $totals; // 縦合計結果格納用配列 16 17 public function __construct(array $arr) 18 { 19 $this->row_keys = array_keys($arr); 20 $this->col_keys = array_keys($arr[$this->row_keys[0]]); 21 $this->rows = count($arr); 22 $this->cols = count($arr[$this->row_keys[0]]); 23 $this->totals = array_fill(0, $this->cols, 0); 24 25 $this->validate($arr); 26 27 $this->arr = $arr; 28 } 29 30 /** 31 * 入力配列のバリデーション 32 */ 33 private function validate(array $arr): bool 34 { 35 for ($i = 0; $i < $this->rows; $i++) { 36 $row = $arr[$this->row_keys[$i]]; 37 $keys = array_keys($row); 38 if (count($keys) !== count($this->col_keys)) { 39 throw new \Exception("与えられた配列 [$arr] がジャグ配列になっています。"); 40 } 41 if (count(array_diff($keys, $this->col_keys))) { 42 $line = $i + 1; 43 throw new \Exception("{$line} 行目の列インデックスと 1 行目の列インデックスが一致しません。"); 44 } 45 $values = array_values($row); 46 for ($j = 0; $j < count($values); $j++) { 47 if (!is_int($values[$j])) { 48 $line = $i + 1; 49 $idx = $j + 1; 50 throw new \Exception("{$line}{$idx} 列の値が、整数ではありません。"); 51 } 52 } 53 } 54 return true; 55 } 56 57 /** 58 * table header の生成 59 */ 60 public function get_header(): string 61 { 62 $header = "<th></th>"; 63 for ($i = 0; $i < $this->cols; $i++) { 64 $header .= "<th>{$this->col_keys[$i]}</th>"; 65 } 66 $header .= "<th>横合計</th>"; 67 68 return $header; 69 } 70 71 /** 72 * table body の生成 73 */ 74 public function get_body(): string 75 { 76 $body_rows = ""; 77 for ($r = 0; $r < $this->rows; $r++) { 78 $body_rows .= $this->get_body_row($r); // <tr/>の生成 79 } 80 81 return $body_rows; 82 } 83 84 /** 85 * table body tr の生成 86 */ 87 private function get_body_row(int $r): string 88 { 89 $row_key = $this->row_keys[$r]; 90 $row = $this->arr[$row_key]; 91 $columns = "<th>{$row_key}</th>"; 92 $sum = 0; 93 for ($c = 0; $c < $this->cols; $c++) { 94 $col_key = $this->col_keys[$c]; 95 $val = $row[$col_key]; 96 $columns .= "<td>{$val}</td>"; 97 $sum += $val; 98 $this->totals[$c] += $val; 99 } 100 $columns .= "<td>{$sum}</td>"; 101 102 return <<< EOL 103<tr> 104{$columns} 105</tr> 106EOL; 107 } 108 109 /** 110 * table footer の生成 111 */ 112 public function get_footer(): string 113 { 114 $footer = "<th>縦合計</th>"; 115 $sum = 0; 116 for ($i = 0; $i < $this->cols; $i++) { 117 $footer .= "<td>{$this->totals[$i]}</td>"; 118 $sum += $this->totals[$i]; 119 } 120 $footer .= "<td>{$sum}</td>"; 121 122 return $footer; 123 } 124}

note

こうした、コードの整理の事をリファクタリングと呼びますが、
ここで提示したコードは完全なリファクタリングを 10 と仮定した場合の 2 程度に相当します。
より高品質の望ましいコードは、最初期のコードの流れとは大きく異なってくるため、ここでは割愛し、本コードまでに留めました。

投稿2021/11/02 19:41

編集2021/11/02 21:57
angel-sun

総合スコア64

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

n_k23

2021/11/03 00:29

angel-sun様 回答誠にありがとうございます。 二つも回答してくださり本当に勉強になります。 回答内容をしっかりと復習し勉強していきます。
guest

0

こんばんは、天使です。

実務を意識したメンテナンス性の高いコードを書く癖をつける事を考慮すると、
第一段階としてはこのようなコードとなるでしょう。
より高度なコードは、このコードの発展型となります。

コーディング・ポリシー

このコードは、後々 logic と view を分ける事を想定して記述されました。
function は敢えて用いませんでした。
使用する組み込み関数も極力少なくし、初歩的なコードで記述しています。

設計

このコードは、入力される配列に制約を設けない設計になっています。
具体的に言うと、正規化された多次元配列であれば配列内のキー・リテラルが何であっても動作します。r*, c*である必要はありません。行数・列数共に可変許容です。
ジャグ配列は不正としています。整数値以外の値も不正としています。

PHP

1<?php 2/** 3 * 表示イメージ 4 * _________________________ 5 * |_____|_c1|_c2|_c3|横合計| 6 * |___r1|_10|__5|_20|___35| 7 * |___r2|__7|__8|_12|___27| 8 * |___r3|_25|__9|130|__164| 9 * |縦合計|_42|_22|162|__226| 10 * ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ 11*/ 12 13///////////////////////////////////////////// 14// 入力 15$arr = [ 16 'r1' => ['c1' => 10, 'c2' => 5, 'c3' => 20], 17 'r2' => ['c1' => 7, 'c2' => 8, 'c3' => 12], 18 'r3' => ['c1' => 25, 'c2' => 9, 'c3' => 130] 19]; 20 21///////////////////////////////////////////// 22// 初期定義 23$row_keys = array_keys($arr); // 行インデックスのリスト 例)["r1", "r2", "r3"] 24$col_keys = array_keys($arr[$row_keys[0]]); // 列インデックスのリスト 例)["c1", "c2", "c3]; 25$rows = count($arr); // 行数 26$cols = count($arr[$row_keys[0]]); // 列数 27$totals = []; // 縦合計結果格納用配列 28 29///////////////////////////////////////////// 30// 入力配列のバリデーション 31for($i = 0; $i < $rows; $i++) 32{ 33 $row = $arr[$row_keys[$i]]; 34 $keys = array_keys($row); 35 if(count($keys) !== count($col_keys)) 36 { 37 echo "与えられた配列 [$arr] がジャグ配列になっています。"; 38 exit; 39 } 40 if(count(array_diff($keys, $col_keys))) 41 { 42 $line = $i + 1; 43 echo "{$line} 行目の列インデックスと 1 行目の列インデックスが一致しません。"; 44 exit; 45 } 46 $values = array_values($row); 47 for($j = 0; $j < count($values); $j++) 48 { 49 if(!is_int($values[$j])) 50 { 51 $line = $i + 1; 52 $idx = $j + 1; 53 echo "{$line}{$idx} 列の値が、整数ではありません。"; 54 exit; 55 } 56 } 57} 58 59///////////////////////////////////////////// 60// table header 61$header = "<th></th>"; 62for($i = 0; $i < $cols; $i++) 63{ 64 $header .= "<th>{$col_keys[$i]}</th>"; 65} 66$header .= "<th>横合計</th>"; 67 68///////////////////////////////////////////// 69// table body 70$body_rows = ""; 71for($r = 0; $r < $rows; $r++) 72{ 73 $row_key = $row_keys[$r]; 74 $row = $arr[$row_key]; 75 $columns = "<th>{$row_key}</th>"; 76 $sum = 0; 77 for($c = 0; $c < $cols; $c++) 78 { 79 $col_key = $col_keys[$c]; 80 $val = $row[$col_key]; 81 $columns .= "<td>{$val}</td>"; 82 $sum += $val; 83 $totals[$c] = isset($totals[$c]) ? $totals[$c] + $val : $val; 84 } 85 $columns .= "<td>{$sum}</td>"; 86 $body_rows .= <<< EOL 87<tr> 88 {$columns} 89</tr> 90EOL; 91} 92 93///////////////////////////////////////////// 94// table footer 95$footer = "<th>縦合計</th>"; 96$sum = 0; 97for($i = 0; $i < $cols; $i++) 98{ 99 $footer .= "<td>{$totals[$i]}</td>"; 100 $sum += $totals[$i]; 101} 102$footer .= "<td>{$sum}</td>"; 103 104///////////////////////////////////////////// 105// 出力 106?> 107<body> 108<?php 109echo <<< EOL 110<table> 111 <thead> 112 <tr> 113 {$header} 114 </tr> 115 </thead> 116 <tbody> 117 {$body_rows} 118 </tbody> 119 <tfoot> 120 <tr> 121 {$footer} 122 </tr> 123 </tfoot> 124</table> 125EOL; 126?> 127</body> 128<style> 129table { 130 border:1px solid #000; 131 border-collapse: collapse; 132} 133th, td { 134 border:1px solid #000; 135 text-align: right; 136 padding: 4px 6px; 137} 138</style>

入力配列の変更例

PHP

1// 入力 2$arr = [ 3 'r1' => ['c1' => 10, 'c2' => 5, 'c3' => 20, "b1" => 10, "b2" => 20, "b3" => 40, "b4" => 60], 4 'r2' => ['c1' => 7, 'c2' => 8, 'c3' => 12, "b1" => 10, "b2" => 1, "b3" => 5, "b4" => 7], 5 'r3' => ['c1' => 25, 'c2' => 9, 'c3' => 130, "b1" => 38, "b2" => 62, "b3" => 51, "b4" => 18], 6 'r4' => ['c1' => 10, 'c2' => 5, 'c3' => 20, "b1" => 10, "b2" => 20, "b3" => 40, "b4" => 60], 7 'r5' => ['c1' => 7, 'c2' => 8, 'c3' => 12, "b1" => 10, "b2" => 1, "b3" => 5, "b4" => 7] 8];
実行結果

入力配列を変更した実行結果

投稿2021/11/02 18:26

編集2021/11/02 20:26
angel-sun

総合スコア64

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

PHP

1$a = [ 2 'r1' => ['c1' => 10, 'c2' => 5, 'c3' => 20], 3 'r2' => ['c1' => 7, 'c2' => 8, 'c3' => 12], 4 'r3' => ['c1' => 25, 'c2' => 9, 'c3' => 130] 5 ]; 6$b=array_map(function($x){ 7 return array_merge($x,["横合計"=>array_reduce($x,function($y,$z){ 8 return $y+$z; 9 })]); 10},array_merge($a,["縦合計"=>array_reduce($a,function($x,$y) use($a){ 11 foreach(array_keys(array_values($a)[0]) as $key){ 12 $x[$key]=(isset($x[$key])?$x[$key]:0)+$y[$key]; 13 } 14 return $x; 15})])); 16$table="<table><tr><th>&nbsp;</th>"; 17for($i=0;$i<count(array_values($b)[0]);$i++){ 18 $table.="<th>".array_keys(array_values($b)[0])[$i]."</th>"; 19} 20$table.="</tr>"; 21for($j=0;$j<count($b);$j++){ 22 $table.="<tr><th>".array_keys($b)[$j]."</th>"; 23 for($i=0;$i<count(array_values($b)[$j]);$i++){ 24 $table.="<td>".array_values(array_values($b)[$j])[$i]."</td>"; 25 } 26 $table.="</tr>"; 27} 28print $table;

投稿2021/11/02 10:31

yambejp

総合スコア115012

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

n_k23

2021/11/02 10:47

yambejp様 回答誠にありがとうございます。 回答内容を自分で精査しながら復習をしていきます。 この方法についての参考になる解説、資料、URL等が ありましたら教えてもらえないでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問