- 投稿日:2020-08-30T17:24:55+09:00
PHPStormとdocker上のxdebugとの連携に詰まったら。トラブルシューティング
これはなに
PHPStormとdocker上のxdebugを連携したいケースで、
「なんで繋がんないんだよ!!」ってなったので、
ヒントになることを書きます。Xdebugとは?
Xdebugとは高機能なPHPのデバッグツールです。 PHPのデバッグでおなじみの「var_dump」を見やすくしてくれたり、ボトムネックになっている処理を見つけたり、ステップ実行できたりします。 その他のデバッグツールとしてはZendDebuggerがあります。
Xdebugを使い倒す5つのTIPS | スマホサイト・アプリをつくろう。
より。ログを有効化する
xdebug.iniやphp.iniに設定を追加しましょう。
追加したらnginxやapacheの再起動が必要です。xdebug.remote_log=/tmp/xdebug.log/tmp/xdebug.logにログが表示されますので、
出力されたエラー内容を見て、原因を特定しましょう。
ググれば関連する情報が出てきます。
ログを見ないで疎通させようとするのは、地図を持たないで山に入るようなもんです。そもそもxdebugの設定が読み込まれているか?
xdebugの設定を記載してもxdebugが動かない、ログも出ないときは
phpに設定が読み込まれているか確認しましょう。
xdebug.soの読み込み忘れでxdebugが動いていなかったり、
別のファイルで設定が上書きされていた、なんてこともありえます。下記のコマンドは、phpに読み込まれている設定値を出力するものです。
xdebugが有効になっている場合は、xdebug関係の設定がいくつか出力されます。php -r 'phpinfo();' | grep xdebug
| grep xdebug
の部分は絞り込みをしています。PHPStorm上のPath Mappingが設定されているか?
docker上のファイルパスと、ローカルPC上のファイルパスのマッピングを設定する必要があります。
index.phpにブレークポイントを設定する
ブラウザからアクセスされた時に必ず実行されるところにブレークポイントを貼ってみましょう。
laravelだとpublic/index.php
です。
これで、xdebugが動いていないのか、ブレークポイントの追加する場所が悪いのか原因の切り分けができます。以上、参考になりましたら幸いです。
参考
https://qiita.com/haruna-nagayoshi/items/99fa041e884c2c3975d2
https://qiita.com/castaneai/items/d5fdf577a348012ed8af
https://qiita.com/taniai-lvgs/items/8e9eba112d2d0ed2530f
- 投稿日:2020-08-30T16:29:41+09:00
久しぶりにmac向けXAMPPをインストールしたら一味違っていた件
結論
- VMになっていた
http://localhost~
じゃなくhttp://{IPアドレス}~
でアクセスするXAMPPのインストールをする
2020/08/30時点のバージョンは7.4.9
finderにできるはずのXAMPPフォルダがなくなっていることに気づく
とりあえずXAMPPをスタートさせてみた
するとなんだかローカルIPアドレスが割り振られたように見える
ApacheとMySQLもスタートさせておく
80ポートをenableにする
mountをクリックする
この
opt/lampp
の中にあるhtdocsがドキュメントルートになるようだ。ここまでいくとfinderの"場所"にVMのIPアドレスが表示されていてフォルダが操作できるようになる
- 投稿日:2020-08-30T16:21:34+09:00
【初心者開発日誌】PHPで楽天APIを使ってみたい #1
昨日までの開発内容をまとめて書きます。
PHPのインストール
実は先月、4年間愛用していたMBPが壊れてしまい、今月から初めてwindowsを使っています。
プログラミングの環境も全く整っていないのでまずはここからになりました。
macはPHPのインストールが不要であるため初めてのインストール。
パスを通さないとコマンドラインでPHPを実行できないことすら知りませんでした。>php -v 'php' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。パスが通っていないのでこの表示になり驚くところからスタート。
パスを通す際、エクスプローラーに「パスのコピー」というボタンがあるのに気づくまで何度も誤字を出しました。参考にしたサイト:
【Windows編】今すぐ簡単にできる!PHPのダウンロード方法Gitプロジェクトの作成
勉強用の開発なのでついでにGitも使ってみることにしました。
ローカルとGitHub上にリポジトリを作成し、Sourcetreeで扱えるようにしています。
初めてのGitなのでまだよくわかっていません。なんとなくブランチを切って開発するのは便利そうだなと思いました。
これから勉強していきます。とりあえずPHPファイルを作る
とりあえず4つ作ってみました。これから構成を変えるかもしれないです。
エンジニアの方々が命名のセンスをどこで身につけるのか知りたいです。home.php
キーワード検索、カテゴリ検索のフォームを置きました。
search.php
検索結果を一覧で見られるようにする予定です。
recipe.php
検索してヒットしたレシピ本体を表示する予定です。
user.php
ログイン機能をつけて検索したレシピを保存したりしたいな、と思ったのでユーザ情報を出すファイルも作りました。
楽天APIの使い方を調べる
こちらに簡単な使い方が書いてありました。楽天グループは本当に親切な企業だと思います。
アプリのURLを登録して、アプリIDを発行すると使えるようです。
ということは先にURLが必要になるので、先程作った空っぽのプロジェクトをどこかに公開しなければならない!と判断しました。
これについては後述します。さて、アプリIDを手に入れたあと、肝心のAPIの使い方を調べました。
リクエストURLを用いてAPIを呼び出し
↓
JSON形式でデータが返ってくる
↓
PHPの配列に変換
というステップを踏むことでレシピの情報が返ってくるようです。
よくわからないので別で用意したファイルでやってみることにしました。サイトの公開
前述のとおりアプリIDの取得にサイトのURLが必要だったため、一旦空っぽのサイトを公開することになりました。
こちらの記事を見ながら進めました。
無料でできるPHPのwebサイト公開(テスト用)公開まではスムーズに進めることができ、アプリIDの取得も完了しています。
- 投稿日:2020-08-30T15:36:12+09:00
【初心者開発日誌】PHPで楽天APIを使ってみたい #0
外部API連携をやってみたい初心者の開発日誌です。
かなり初歩的な内容になると思います。
記録として記事を残し、あとで見て笑い飛ばせるようになればと思います。経緯
私はいま大学3年生で、将来漠然とエンジニアになりたいと思っています。
ですが自分がやりたい分野がどこなのかいまいちわかっていません。
そこでとある人にもらったアドバイスが、「webサービスを1から自力で作ってみて一番楽しかった工程が向いているのではないか」というものでした。
また、先日ある短期インターンに参加したのですが、内容が「APIを用いた開発をしてみよう!」で、APIを使ったことのない私はわけもわからず状態になってしまいました。この悔しさから自力で作るwebサービスには必ずAPIを組み込もうと決めました。実は数日前から開発を進めているのですが、なかなか思うようにいかず勉強の毎日です。そこで開発日誌を残せばあとあと面白いのではないか?と思い開発日誌を書くに至りました。
目標
最近料理にはまっているので、楽天レシピ系APIを使ってレシピ検索サイトを作ることを目標にしました。
カテゴリ検索ができるようにする
↓
キーワード検索ができるようにする
↓
ユニークな検索オプションをつける
↓
他社のレシピサイトとも連携という順にクリアしていきたいと思います。
https://webservice.rakuten.co.jp/api/recipecategorylist/
https://webservice.rakuten.co.jp/api/recipecategoryranking/
- 投稿日:2020-08-30T13:13:29+09:00
【Laravel実践】リクエストパラメータ名をスネークケースに変換する方法
Version
- Laravel 5.7
- PHP 7.2.31
前提
LaravelでAPIを開発する際、キャメルケースとして書かれたリクエストパラメータ名をスネークケースに変換したい、という要望を想定します。たとえば、SPA開発においてReact.jsやVue.jsにより非同期通信でLaravelのAPIにリクエストを送信する際、フロント側としてはキャメルケースで統一したいがバックエンド側としてはスネークケースで統一したい、というケースです。
Laravel側で簡単に変換する方法をググったのですが、ベストプラクティス的な方法が出てこなかったのでここに共有します。
早速、変換してみよう。
結論だけ述べると、以下の方法で実現できます。
$request->all()
でリクエストパラメータを受け取り、リクエストパラメータ名($key
)に大文字が含まれる場合にスネークケースに変換・挿入、offsetUnset()
で元のプロパティ名を消す、ということをやっています。foreach ($request->all() as $key => $value) { if(preg_match('/[A-Z]/', $key)){ $new_key = Str::snake($key); $request->merge([$new_key => $request->$key]); $request->offsetUnset($key); } }たとえば、TestControllerのindexで受け取ることを考えてみましょう。バリデーションを一旦無視すれば、以下のように書けるはずです。
TestController.phpclass TestController { public function index(Request $request) { // スネークケースに変換する処理 foreach ($request->all() as $key => $value) { if(preg_match('/[A-Z]/', $key)){ $new_key = Str::snake($key); $request->merge([$new_key => $request->$key]); $request->offsetUnset($key); } } // hogehoge処理 ... return $request; } }応用: スネークケース変換用のクラスを作成
色々と応用する方法はあると思いますが、最終的に以下の方法で落ち着きました。
- FormRequestクラスでバリデーション処理(※1)
- Controllerクラスを継承する形でスネークケースに変換するクラスを作成(※2)
- indexのController側でスネークケース変換用のメソッドを呼び出し(※3)
NormalizedController.php// ※2 class NormalizedController extends Controller { /** * Change request parameter from camel case to snake case * * @param object $request * @return object */ protected function normarize_request(Object $request) : object { foreach ($request->all() as $key => $value) { if(preg_match('/[A-Z]/', $key)){ $new_key = Str::snake($key); $request->merge([$new_key => $request->$key]); $request->offsetUnset($key); } } return $request; } }TestController.php// FormRequestクラス(※1) use App\Http\Requests\Test\GetRequest; class TestController extends NormalizedController { public function index(GetRequest $request) { // 呼び出し(※3) $this->normarize_request($request); // hogehoge処理 ... return $request; } }参照
- 投稿日:2020-08-30T02:51:51+09:00
CodeIgniter3 から Laravel へ。文化の異なるフレームワークへ飛び込む上で,ハードルになりそうなパッケージ管理システムの概要を解説
概要
今回は,より高度な(実用的な)仕様の例題を設定し,CodeIgniter と Laravel のコードを対比させていきたいと思います。
具体的には,CSS と JS を組み込んだページを作成したいと思いますが,具体的なコードの紹介は次回の記事にゆだね,今回は,もっと基本となる「パッケージ管理システム」について触れます。
あまり一気に難しくならないよう,極力配慮したいと思いますが,前回よりは,ハードルがぐーんと高くなり,おじさんの言語化能力で,どこまで的確に表現できるか,冷や汗をかきそうです(プレッシャーの重圧感)。
マサカリ歓迎案件です(いろいろ教えてください)。
Laravel で登場する,2つのパッケージ管理システム
どのタイミングで話すべきか迷ったのですが,いずれ書かねばならないことなので,今のタイミングにします。
「軽量であること」を強みとする CodeIgniter は,フレームワークと言うより,フォルダ構造を決めただけの,ファイルの集合体に近いですね(そんな言い方をしてしまうと,世の中のすべてのフレームワークが,「ファイルの集合体」と言えますが……)。
一方,Laravel も「ファイルの集合体」ではありますが,「パッケージ管理システム」が標準的な仕組みとして多用されることが大きな相違点です。
※パッケージ管理システムをまったく使わず,Laravel で開発するのも可能かと思いますが,ほとんどメリットはないと思います(しんどくなるだけ)
※「パッケージ管理システムが何であるか」は,優れた記事が多数あるため,本記事の記述スコープに含めません
しかも,驚くなかれ,Laravel には,二種類のパッケージ管理システムが採用されています:
Composer
バックエンド側(PHP ファイル)のパッケージ管理を担うLaravel Mix
フロントエンド側(CSS / JS ファイル)のパッケージ管理を担うどっちか一つを使うというものではなく,役割がそもそも異なっているのですね(バックエンド側か,フロントエンド側か)。
以下,もっと具体的に見ていきましょう。
プロジェクト新規作成
CodeIgniter は,公式サイトから zip としてダウンロードする方法。
あくまでも,開発者が,ブラウザで公式サイトへアクセスし,そこからファイル一式を取得するというスタンスですね。
一方,Laravel では,Composer というパッケージ管理システムを使って,コマンドラインからプロジェクトのファイル一式を生成します。
たとえば,
example
という名のプロジェクトを生成するには,以下のようなコマンドを実行します:composer create-project --prefer-dist laravel/laravel exampleCodeIgniter に慣れていると,つい,手作業でファイルを追加したり,移動したりする衝動に駆られてしまいますが,そこはグッと我慢することが,Laravel 文化の入り口です。
最後に,もう一度まとめます:
工程 CodeIgniter Laravel テンプレート一式の取得 公式サイトから zip をダウンロード Composer
コマンド経由で取得PHP ファイルの追加
CodeIgniter で新しい PHP ファイル(例:コントローラ)を追加するときには,テキストファイルをコピペする感覚で,みんな大好き
Ctrl + C
やCtrl + P
のショートカットが大活躍でした。一方,Laravel では,新しい PHP ファイル(例:コントローラ)を追加するときには,パッケージ管理システム Composer を使って,コマンドライン上で実行します。
たとえば,
MyFirstController
というコントローラを作る場合,以下のようなコマンドを実行します:php artisan make:controller MyFirstControllerLaravel でも,
Ctrl + C
とCtrl + P
で,新しい PHP ファイルを生成可能(例:既存のクラスからコピーして生成可能)ですが,コピー後のファイルの中身を,自分で書き換える手間が生じるので,あまりスマートな方法だとは言えません。最後に,もう一度まとめます:
工程 CodeIgniter Laravel PHP ファイルの追加 Ctrl + C
とCtrl + P
で手動対応Composer
コマンド経由で作成CSS / JS ファイルの追加
CSS / JS ファイルといった,フロントエンドのアセットを生成するケースを考えます。
「ファイルの集合体」のようにシンプルな CodeIgniter では,所定のフォルダへ,CSS や JS を保存するだけ(&その後,ビュー側の
<head></head>
部で,読み込ませるだけ)。Laravel でも,所定のフォルダへ,CSS / JS を保存するという,CodeIgniter 時代のスタイルは利用可能です。
一方,Laravel では,もう一つのパッケージ管理システム Laravel Mix を使うというオプションも,用意されています。
超ざっくり書くと,以下のような役割を果たしてくれます。
- 依存関係のあるライブラリを一括取得(一番「親」のライブラリを指定すると,配下の関連ライブラリを,芋づる式に,拾ってきてくれます)
- リリースしやすいよう,関連ファイルを,一つのファイルにまとめてパッキング
コマンドラインでは,
npm run dev
とすれば,開発環境でデバッグが容易な(人の目で見ても解釈しやすい)形式にパッキングしてくれます。一方,
npm run production
とすれば,リリースに適した形式(空白や改行を除外し,コンピュータの解釈に適したもの。ファイルサイズとしても,すごく小さくなる)にパッキングしてくれます。ひとつ強調しておくと,Laravel Mix は,その名に 'Laravel' を冠しながらも,Laravel 利用の有無とは関係なく使える,パッケージ管理システムだったりします。
つまり,CodeIgniter でも,Laravel Mix を活用することは可能です。
最後に,もう一度まとめます:
工程 CodeIgniter Laravel CSS / JS ファイルの追加 所定フォルダに,手動で保存 Laravel Mix
利用まとめ
かなり駆け足になりましたが,CodeIgniter では手作業メインで行っていたファイル管理を,Laravel では,コマンドライン経由で済ませるのだという理解を形成いただければ,本記事のリリース目的は達成されました。
事実,コマンドラインで,パッケージ管理システムを上手に活用し,エンジニアが本来注力すべき作業へ集中させてくれるようになっているのは,Laravel のコンセプトでもあるように感じます。
次回では,実際に,パッケージ管理システムを操作しながら,Laravel を用いたフロントエンドアセット(CSS / JS)の組み込みについて,CodeIgniter と比較させながら見ていきたいと思います。
- 投稿日:2020-08-30T02:37:37+09:00
[PHPの基礎筋力向上]競プロの問題をPHPで解いていこう!
この記事の対象読者
- paizaでランクアップを目指す(Aランクくらいまで)の未経験/駆け出しエンジニア
- ドットインストールや入門書籍でPHPを学んだが、まだ”手に馴染んでいない”初学者
この記事を書いた目的
書籍やドットインストール等のオンライン学習教材でプログラミング言語を学んだ初学者がいきなりWebサイトを作るのは中々ハードルが高いです。
そういった初学者にオススメしたいのが簡単なプログラミング問題を解いて練習することです。
この練習を通して「サービスの企画に力を分散させることなく、純粋にコーディング能力を鍛える」ことが出来ます。これは後々Webサービスを開発する上でも絶対に役立つ基礎力になるはずです。
これは未経験からソフトウェア開発職にキャリアチェンジしたい方にもオススメのやり方です。
例えばpaizaというコーディングテストを受けて就職活動が出来るサービスではAランクくらいまで取れればかなりの数の企業に”エントリーシートなしで”面接することが出来ます。またpaiza以外の媒体で面接した企業の方にも「paizaでAランクある」と伝えると中々好評でした。ただ、paizaの問題は基本的に外部で解説等することが禁止されているので今回はAOJ-ICPCというサイトを使って一番基礎的なレベル100の問題(一番下といってもpaizaでBランククラスはあるかと思います。)を丁寧に解説しながら解いていこうと思います!
※まぁ結論すごく面白いしコーディングの筋力アップに繋がるしついでに(paizaでランクも取れて)就職でも有利になるのでワイとAOJ-ICPCやろうズ!
下準備
- VSCode編 PHPのプラグイン入れる code-runner入れる ->執筆予定! # 下準備 Vim編 Vimの練習も同時にしたいんだ!というツワモノはこちらを参考にしてください。
「Vimでのpaiza下準備をステップバイステップで丁寧に」
問題を理解する
今回取りあげるのはICPC 得点集計ソフトウェアという問題です。
まず問題を解く前に(特に初学者のみなさんは)問題文を音読で読んでしっかり理解するようにしてください。
読めましたか?余裕がある方は下を読んでいく前に自力で解いていきましょう。(その際はメモ帳片手にどういうロジックで解いていくか考えながらやってみましょう!)
まずどういうデータが与えられるのかを考える
- 審査員の人数nが与えられる。(3 <= n <= 10)
- その後に審査員の数だけ点数sが与えられる。(0 <= s <= 1000)
- 入力の終わりには審査員の数に0が与えられる。
以上から下記のような形式でデータが与えられるとわかります。
//inputは下記のような形式で与えられる。 審査員の人数n s_1 s_2 s_3 . . . s_n-1 s_n 審査員の人数m s_1 s_2 . . . s_m 0 ->ここで入力おわり!
- どういう答えを出すべきか
演技の点数は審査員の出した点数の合計から最大値と最小値を引く。
その後、審査員の数から最大値と最小値を出した審査員分だけ(2)引く数で割る。
点数は『平均点には端数があるかもしれないが,それは切り捨てて最終的な点数は整数値』とすること。まずはベタ書きの処理をコーディングしてみる
- 審査員の人数を取得
標準入力を取得するにはfgets(STDIN)。
標準有力はstring型(文字)として取得されるので型キャストする。(int)でint型になる。$judge_num = (int) fgets(STDIN);
- 審査員の数だけスコアを取得、それを配列に入れていきます。
$score_list = []; for($i=0;$i<$judge_num;$i++){ $score_list[] = (int)fgets(STDIN); }
- 最大値と最小値を除いた平均(調整平均)を計算
配列の合計、最大値、最小値を取得するにはarray_sum関数とmax関数、min関数。
平均の値は小数点を切り捨てするように、と問題文にあるのでfloor関数を使用しましょう。$max_num = max($score_list); $min_num = min($score_list); $score_sum = array_sum($score_list) - $max_num - $min_num; $adjusted_ave_score = floor($score_sum / ($judge_num - 2));これで一回の審査分の点数を算出できます。
ただ、今回は審査員数0となるまで点数を出すようにしたいです。
何回処理をするかがわからない。。。そんなときはforループではなくwhile文を使いましょう。while(True){ $judge_num = (int) fgets(STDIN); //審査員の数が0のときwhileループがbreakされる。 if ($judge_num === 0){ break; } //処理 . . . }以下が完成品です。
<?php while(True){ //審査員の数を取得 $judge_num = (int) fgets(STDIN); if ($judge_num === 0){ break; } //スコアを配列に入れていく $score_list = []; for($i=0;$i<$judge_num;$i++){ $score_list[] = (int)fgets(STDIN); } //最大値と最小値を取得 $max_num = max($score_list); $min_num = min($score_list); //調整平均を算出 $score_sum = array_sum($score_list) - $max_num - $min_num; $adjusted_ave_score = floor($score_sum / ($judge_num - 2)); echo $adjusted_ave_score . PHP_EOL; }関数化してみる
関数とはPHP本格入門 [上]/大家正登 著によれば、『人間にとって意味を持つ一連のプログラム処理をまとめ、オリジナルな名前を持つ一つの命令として扱えるようにする』ものです。
関数を使うメリットは、
(1)DRYなコードになる(コピペで何箇所にもプログラム処理を書く必要がなくなる)
(2)可読性の向上(後で読み返した時に関数の名前付けやコメントをしっかり書いておけば処理の中身を読み込む手間なく何をしているのかわかる)の2つです。
今回はいきなり完成品を示します。
<?php function get_input_num(){ $input_num = (int) fgets(STDIN); return $input_num; } function make_score_list($judge_num){ $score_list = []; for($i=0;$i<$judge_num;$i++){ $score_list[] = get_input_num(); } return $score_list; } function calculate_adjusted_ave_score($judge_num, $score_list){ $max_num = max($score_list); //echo $max_num; $min_num = min($score_list); //echo $min_num; $score_sum = array_sum($score_list) - $max_num - $min_num; $adjusted_ave_score = $score_sum / ($judge_num - 2); return $adjusted_ave_score; } while(True){ //審査員の人数を取得 $judge_num = get_input_num(); //審査員の数値が0のとき入力終わり、whileから抜け出す if ($judge_num === 0){ break; } //echoで数値を確認しながらコーディングしていこう!必要なくなったらコメントアウト //echo $judge_num; //スコアを配列に入れてやる $score_list = make_score_list($judge_num); //配列はvar_exportで確認してみよう! //var_export($score_list); //最大値と最小値を除いた調整平均を出す $adjusted_ave_score = calculate_adjusted_ave_score($judge_num, $score_list); //小数点は切り捨て $adjusted_ave_score = floor($adjusted_ave_score); echo $adjusted_ave_score . PHP_EOL; }自分で書いてみよう!(他のロジックを考える)
たとえばスコアを配列で取得してmax、min関数を使うというロジックから。。。
max_num = -1 min_num = 1001と設定してこれらの変数とスコアを標準入力から取得するたびに比較して更新していくなど。
他にどんなロジックを使えば書けるのか考えていきましょう!
- 投稿日:2020-08-30T02:37:37+09:00
[PHP基礎体力向上]競プロ(AOJ-ICPC)の基礎問題をPHPで解いていこう!
この記事の対象読者
- paizaでランクアップを目指す(Aランクくらいまで)の未経験/駆け出しエンジニア
- ドットインストールや入門書籍でPHPを学んだが、まだ”手に馴染んでいない”初学者
この記事を書いた目的
書籍やドットインストール等のオンライン学習教材でプログラミング言語を学んだ初学者がいきなりWebサイトを作るのは中々ハードルが高いです。
そういった初学者にオススメしたいのが簡単なプログラミング問題を解いて練習することです。
この練習を通して「サービスの企画に力を分散させることなく、純粋にコーディング能力を鍛える」ことが出来ます。これは後々Webサービスを開発する上でも絶対に役立つ基礎力になるはずです。
これは未経験からソフトウェア開発職にキャリアチェンジしたい方にもオススメのやり方です。
例えばpaizaというコーディングテストを受けて就職活動が出来るサービスではAランクくらいまで取れればかなりの数の企業に”エントリーシートなしで”面接することが出来ます。またpaiza以外の媒体で面接した企業の方にも「paizaでAランクある」と伝えると中々好評でした。ただ、paizaの問題は基本的に外部で解説等することが禁止されているので今回はAOJ-ICPCというサイトを使って一番基礎的なレベル100の問題(一番下といってもpaizaでBランククラスはあるかと思います。)を丁寧に解説しながら解いていこうと思います!
※まぁ結論すごく面白いしコーディングの筋力アップに繋がるしついでに(paizaでランクも取れて)就職でも有利になるのでワイとAOJ-ICPCやろうズ!
下準備
VSCode編
PHPのプラグイン入れる
code-runner入れる
->執筆予定!Vim編
Vimの練習も同時にしたいんだ!というツワモノはこちらを参考にしてください。「Vimでのpaiza下準備をステップバイステップで丁寧に」
問題を理解する
今回取りあげるのはICPC 得点集計ソフトウェアという問題です。
まず問題を解く前に(特に初学者のみなさんは)問題文を音読で読んでしっかり理解するようにしてください。
読めましたか?余裕がある方は下を読んでいく前に自力で解いていきましょう。(その際はメモ帳片手にどういうロジックで解いていくか考えながらやってみましょう!)
まずどういうデータが与えられるのかを考える
- 審査員の人数nが与えられる。(3 <= n <= 10)
- その後に審査員の数だけ点数sが与えられる。(0 <= s <= 1000)
- 入力の終わりには審査員の数に0が与えられる。
以上から下記のような形式でデータが与えられるとわかります。
//inputは下記のような形式で与えられる。 審査員の人数n s_1 s_2 s_3 . . . s_n-1 s_n 審査員の人数m s_1 s_2 . . . s_m 0 ->ここで入力おわり!
- どういう答えを出すべきか
演技の点数は審査員の出した点数の合計から最大値と最小値を引く。
その後、審査員の数から最大値と最小値を出した審査員分だけ(2)引く数で割る。
点数は『平均点には端数があるかもしれないが,それは切り捨てて最終的な点数は整数値』とすること。まずはベタ書きの処理をコーディングしてみる
- 審査員の人数を取得
標準入力を取得するにはfgets(STDIN)。
標準有力はstring型(文字)として取得されるので型キャストする。(int)でint型になる。$judge_num = (int) fgets(STDIN);
- 審査員の数だけスコアを取得、それを配列に入れていきます。
$score_list = []; for($i=0;$i<$judge_num;$i++){ $score_list[] = (int)fgets(STDIN); }
- 最大値と最小値を除いた平均(調整平均)を計算
配列の合計、最大値、最小値を取得するにはarray_sum関数とmax関数、min関数。
平均の値は小数点を切り捨てするように、と問題文にあるのでfloor関数を使用しましょう。$max_num = max($score_list); $min_num = min($score_list); $score_sum = array_sum($score_list) - $max_num - $min_num; $adjusted_ave_score = floor($score_sum / ($judge_num - 2));これで一回の審査分の点数を算出できます。
ただ、今回は審査員数0となるまで点数を出すようにしたいです。
何回処理をするかがわからない。。。そんなときはforループではなくwhile文を使いましょう。while(True){ $judge_num = (int) fgets(STDIN); //審査員の数が0のときwhileループがbreakされる。 if ($judge_num === 0){ break; } //処理 . . . }以下が完成品です。
<?php while(True){ //審査員の数を取得 $judge_num = (int) fgets(STDIN); if ($judge_num === 0){ break; } //スコアを配列に入れていく $score_list = []; for($i=0;$i<$judge_num;$i++){ $score_list[] = (int)fgets(STDIN); } //最大値と最小値を取得 $max_num = max($score_list); $min_num = min($score_list); //調整平均を算出 $score_sum = array_sum($score_list) - $max_num - $min_num; $adjusted_ave_score = floor($score_sum / ($judge_num - 2)); echo $adjusted_ave_score . PHP_EOL; }関数化してみる
関数とはPHP本格入門 [上]/大家正登 著によれば、『人間にとって意味を持つ一連のプログラム処理をまとめ、オリジナルな名前を持つ一つの命令として扱えるようにする』ものです。
関数を使うメリットは、
(1)DRYなコードになる(コピペで何箇所にもプログラム処理を書く必要がなくなる)
(2)可読性の向上(後で読み返した時に関数の名前付けやコメントをしっかり書いておけば処理の中身を読み込む手間なく何をしているのかわかる)の2つです。
今回はいきなり完成品を示します。
<?php function get_input_num(){ $input_num = (int) fgets(STDIN); return $input_num; } function make_score_list($judge_num){ $score_list = []; for($i=0;$i<$judge_num;$i++){ $score_list[] = get_input_num(); } return $score_list; } function calculate_adjusted_ave_score($judge_num, $score_list){ $max_num = max($score_list); //echo $max_num; $min_num = min($score_list); //echo $min_num; $score_sum = array_sum($score_list) - $max_num - $min_num; $adjusted_ave_score = $score_sum / ($judge_num - 2); return $adjusted_ave_score; } while(True){ //審査員の人数を取得 $judge_num = get_input_num(); //審査員の数値が0のとき入力終わり、whileから抜け出す if ($judge_num === 0){ break; } //echoで数値を確認しながらコーディングしていこう!必要なくなったらコメントアウト //echo $judge_num; //スコアを配列に入れてやる $score_list = make_score_list($judge_num); //配列はvar_exportで確認してみよう! //var_export($score_list); //最大値と最小値を除いた調整平均を出す $adjusted_ave_score = calculate_adjusted_ave_score($judge_num, $score_list); //小数点は切り捨て $adjusted_ave_score = floor($adjusted_ave_score); echo $adjusted_ave_score . PHP_EOL; }自分で書いてみよう!(他のロジックを考える)
たとえばスコアを配列で取得してmax、min関数を使うというロジックから。。。
max_num = -1 min_num = 1001と設定してこれらの変数とスコアを標準入力から取得するたびに比較して更新していくなど。
他にどんなロジックを使えば書けるのか考えていきましょう!