PHP学習 ④

前回の復習から始める。標準入力取得した数値を使ってプログラムにするところで
やはりつまづいてしまった。。。
プログラムが複雑化した時に困らないようこの記述の考え方に慣れておきたい。



プログラミング学習 PHP入門

LESSON 4 : 配列の基礎、explodeを学習する
より高度で柔軟性の高いランダムくじ引きが作れるようになる事を目指す。



★プログラミングで肝となる配列の概念について学ぶ。

図解も多いので動画を閲覧して確認する。
https://paiza.jp/works/php/primer/beginner4/2121

配列とは、変数のようなデータを扱うためのデータ構造の一種。

変数に対して代入できるデータが1つであるのに対して
配列に対しては複数の値や文字列を代入できる。
配列は複数のデータを扱うためのKEY番号を持っていて
このKEYを対応する形でvalue値を代入し、データ管理できる。


配列は、順番を管理したり、並べ替えたり、追加するのに便利。

配列の使いどころとしては
・並び順管理が必要なデータ処理
・エクセルのような複数業のデータ処理
・フォーム等の選択肢の管理(性別、都道府県、etc)
・座席の空席管理
・CSVデータの処理(二次元配列、連想配列)
・将棋のような盤面の表現(二次元配列)


★配列の基本操作について学習していく。
特に配列への代入、配列の中身の出力など。


配列への代入のしかた
$配列名 = array(要素1, 要素2, 要素3,”文字列”,001,$hensuu,…);
配列に代入したい用はカンマ区切りで連ねる事で複数代入できます。
要素1から順にkey番号0から割り振られていく。
※ 要素数の上限はPHP4系だと65536個までで、PHP5系だと4294967296個まで

配列の中身の出力にはprint_r();を使う。
print_r() 関数・・・指定した配列、変数に関する情報を解りやすく出力する。

この関数は配列の中身を全てが表示されるので
基本的には配列の中身を確認するデバッグで利用することが多い。
そのため、配列の中から特定の要素を取り出したい時はechoを使う。



e.g.
<?php
$item = array("ロングソード","ブレードソード","エクスカリバー");

print_r($item);
?>


演習「変数の値を配列に代入してみよう」
右側のエディターエリアに書かれている変数を
配列 $team に代入し、print_rを使って出力してみましょう。

配列への代入順序は、最初に$b、次に$c、最後に$aの
順番で代入してください。

 入力される値
勇者
魔法使い
僧侶

 標準入力からの値取得方法はこちらをご確認ください
 期待する出力値
Array
(
[0] => 魔法使い
[1] => 僧侶
[2] => 勇者
)



<?php
$a = trim(fgets(STDIN));
$b = trim(fgets(STDIN));
$c = trim(fgets(STDIN));

// $a,$b,$cを指定の順番で配列$teamに代入してください

$team = array($b, $c, $a);
print_r($team);

?>

_____________________________________



引き続き配列への値の追加、上書き、削除、特定の値の出力といった、
配列の基本操作について学習する。

配列の中から特定の要素を取り出したい時はechoを使う。
i.e.
$team = array(“勇者”,”魔法使い”,”盗賊”);
echo $team[1];
実行するとkey番号1の魔法使いが出力される


配列の要素の追加、上書き、削除のやり方
要素の追加方法
$array[] = 追加したい要素;
e.g.
$team = array(“勇者”,”魔法使い”,”盗賊”);
$team[] = “踊り子”
実行すると
$teamの配列のkey番号3に踊り子が追加される
またこの要素の追加だけで配列を作ることもできる


要素の上書き方法
$array[上書きしたい要素のキー番号] = 上書きしたい内容;
e.g.
$team = array(“勇者”,”魔法使い”,”盗賊”);
$team[] = “踊り子”
$team[3] = “ヒットマン”
実行すると
$team配列のkey番号3である踊り子がヒットマンに上書きされる


要素の削除方法
unset($array[削除したい要素のキー番号]);
e.g.
$team = array(“勇者”,”魔法使い”,”盗賊”,”猫”);
unset($team[1]);
実行すると、key番号1の魔法使いが削除されるが
この場合、key番号1も歯抜けになって
出力結果は[0][2][3]となり
key番号がくりあがるわけではない点に注意。


演習1「配列から特定要素を取り出す」
以下のプログラムを元に
配列 $team の3つ目に代入されている要素を出力してください。

標準入力される値
勇者
戦士

忍者
魔法使い

<?php
// 標準入力から5行分の入力を配列に代入する
for($i=0; $i < 5; $i++){
    $team[] = trim(fgets(STDIN));
}
// ここから下に記述 
// $team の3つ目の要素を出力してください
echo ($team[2])
?>

出力値

___________________________

これらの配列の基本操作である配列への代入、配列の中身の出力
配列への値の追加、上書き削除、特定の値の出力などは
基礎中の基礎なのでしっかり理解をしておく。



★explode関数を使い、カンマ等で区切られた
文字列を分割して配列に代入するやり方について学ぶ。

$配列名 = explode("分割する区切り文字", 分割したい文字列);

カンマで区切られたCSVデータのような、特定の区切り文字で区切られた文字列を分割して
配列に代入する関数です。CSVデータを扱う際や、URLの分割などに利用します。
e.g.
 $string"= "a/b/c";
 $array = explode("/", $string);
 /で区切られたもじa,b,cを分割して配列に代入します。
 $array[0]にはaが、$array[1]にはbが、$array[2]にはcが代入されます。

ちなみに配列の中身となる要素の数を数えたい場合は
カウント関数を用いて出力する。
i.e.
echo count($array);
カウント関数は配列を使う時には非常によく使うのでしっかり覚えよう。


演習「explodeで文字列を分割してみよう」
標準入力で <> で区切られた文字列が与えられます。
explode関数を使い、<> で分割し、配列に代入して
print_rで配列の中身を出力してみましょう。

 入力される値
勇者<>戦士<>侍<>忍者<>魔法使い

 期待する出力値
Array
(
[0] => 勇者
[1] => 戦士
[2] => 侍
[3] => 忍者
[4] => 魔法使い
)


<?php
$input = trim(fgets(STDIN));

$array = explode("<>", $input);
print_r($array);

?>


演習「配列の中身を数えてみよう」
標準入力でカンマ区切り( , )のデータが1行与えられます。
その中にいくつの要素が入っているかを数えて、その数を出力してください。
例 戦士,侍,忍者 という入力があったら「3」と出力する

 入力される値
勇者,戦士,侍,忍者,武士,騎士,魔法使い,魔導士,僧侶,モンク,狩人

 期待する出力値
11

<?php
// 標準入力から1行取得し$inputに代入
$input = trim(fgets(STDIN));
// カンマ区切りでいくつの要素が入っているか数えよう
$array = explode(",", $input);
echo count($array);
?>


演習「配列の中身を1行づつ表示してみよう」
右側のエディターエリアのプログラムをもとに、標準入力で1行で与えられる
カンマ区切り( , )のデータを、カンマで分割して、各要素を1行ずつ
改行して出力してみましょう。

◆例 
「戦士,侍,忍者」という入力があったら
戦士

忍者
と出力しましょう。

ヒント!
ループで配列から要素を一つづつ取り出す場合は、ループカウンタ($iなど)は、
0から始めるようにしましょう。配列のキー番号は0から始まるからです。

 入力される値
勇者,戦士,侍,忍者,武士

 期待する出力値
勇者
戦士

忍者
武士

模範解答1 for文で書いた場合
<?php
// 標準入力から1行取得し$inputに代入
$input = trim(fgets(STDIN));
// explodeで$inputの文字列を分割し$arrayに配列として代入
$array = explode(",", $input);
// $arrayの要素数を数えて$numに代入
$num = count($array);
// $numの数だけループして$arrayから
for($i=0; $i<$num; $i++){
    // 要素を一つづつ取り出してみよう
    echo $array[$i]."\n";
}
?>


模範解答2 while文で書いた場合
<?php
// 標準入力から1行取得し$inputに代入
$input = trim(fgets(STDIN));
// explodeで$inputの文字列を分割し$arrayに配列として代入
$array = explode(",", $input);
// $arrayの要素数を数えて$numに代入
$num = count($array);
// $numの数だけループして$arrayから
$i=0;
while($i<$num){
    // 要素を一つづつ取り出してみよう
    echo $array[$i]."\n";
    $i++;
}
?>


演習「配列の中身を1行づつ表示してみよう」
標準入力で1行で与えられるカンマ区切り( , )のデータを、
カンマで分割して、各要素を1行ずつ改行して
末尾に「さん」と付けて出力してみましょう。

◆例 
「戦士,侍,忍者」という入力があったら
戦士さん
侍さん
忍者さん
と出力しましょう。

 入力される値
勇者,戦士,侍,忍者,武士

 期待する出力値
勇者さん
戦士さん
侍さん
忍者さん
武士さん

<?php
$input = trim(fgets(STDIN));
$array = explode(",", $input);
$num = count($array);
for($i=0; $i < $num; $i++){
  echo $array[$i]."さん\n";
}
?>

この演習で行った中身に習熟する!


では次に配列にデータを格納する方法について見ていく


★配列にデータを格納する

標準入力からの複数行データ読み込み、配列に格納するやり方について学ぶ。
CSVデータの読み込みや、外部データを読み込んで処理をおこないたい場合に必須の技術。

一般標準入力 
山川
川田
田中

<?php
//データを取得する
$input = trim(fgets(STDIN));
//値が空でなければループして値を取得し続ける
while($input){
$array[] = $input;
$input = trim(fgets(STDIN));
}
print_r($array);
?>

出力すると

Array
(
[0] => 山川
[1] => 川田
[2] => 田中
)

となる


while文の書き方
while(ループを続ける条件式){
// 繰り返し実行する処理
}

while($hoge) と書くと、変数 $hoge の中に何か値が
ある限りwhileループが回り続ける事になります。
$hoge の中が空になった場合($hoge ="";)ループを抜けます。

逆に $hoge の値が空の場合のみループをまわしたい場合は
while(!$hoge) と書きます。





演習「標準入力のすべての行を取得する」
標準入力で行数不明の複数行のデータが入力されます。
右側のエディターエリアのプログラムをもとに、標準入力の全ての行の値に
末尾に「さん」を付けて、1行づつ改行して出力するように書き換えてください。
※配列に追加する必要はありません

 入力される値
勇者
戦士

 期待する出力値
勇者さん
戦士さん


解答
<?php
// 標準入力から1行データを取得
$input = trim(fgets(STDIN));
// $inputの値が空で無ければループする
while($input){
    // ★配列に代入せず「さん」を付けて出力
    echo $input."さん\n";
    // 標準入力から1行データを取得
    $input = trim(fgets(STDIN));
}

?>



演習「勇者を捜せ!」
標準入力で行数不明の複数行のデータが入力されます。
エディターエリアのプログラムをもとに、標準入力から
入力される値が「勇者」となっているものだけを判別して、
全部で勇者が何回登場したかを整数で出力してください。

$inputの中身が勇者かどうか判定し、勇者だけを配列に代入、
ループ終了後に配列の要素数を集計すると簡単に出来ます。

 入力される値
勇者
戦士
勇者

 期待する出力値
2


解答1 count関数を使った方法
<?php
// 標準入力から1行データを取得
$input = trim(fgets(STDIN));
// $inputの値が空で無ければループする
while($input){
    // $inputの値が勇者だったら配列に追加
    if($input == "勇者"){
        $array[] = $input;
    }
    // 標準入力から1行データを取得
    $input = trim(fgets(STDIN));
}
echo count($array);
?>


解答2 出現回数をカウントする変数を使った書き方
<?php
// 標準入力から1行データを取得
$input = trim(fgets(STDIN));
// $inputの値が空で無ければループする
$hero_num = 0;
while($input){
    // $inputの値が勇者だったら配列に追加
    if($input == "勇者"){
        $hero_num++;
    }
    // 標準入力から1行データを取得
    $input = trim(fgets(STDIN));
}
echo $hero_num;
?>




しかし、このやり方には弱点があり
標準入力の途中に空行があった場合
ループを抜けてしまい、最後の行まで読み込まれない。


これを回避するための方法について解説する。
https://paiza.jp/works/php/primer/beginner4/2126

考え方としては、
標準入力の途中の空行には改行コードが入っている
 ↓
改行コードが入っていれば空行とみなさないプログラムに書き換える
 ↓
while文の評価式に改行コードが認識されなければならない
 ↓
データ取得時のトリムを外して配列に代入するときにトリムする

その結果
入力の途中で空行があったとしても最後まで値を取得できる


また標準入力を取得する記述を一つにまとめる方法
→ while文の条件式に入れる
これは、CSVの読み込みの際などにもよく使うので
きちんと書けるようにしておく。




演習「勇者を捜せ!」
標準入力で行数不明の複数行のデータが入力されます。
エディターエリアのプログラムをもとに、標準入力から
入力される値のうち、「勇者」となっているものだけを判別して、
全部で勇者が何回登場したかを整数で出力してください。
※標準入力の途中に空行が入る場合でも最終行まで値を取得してください

 入力される値
戦士

勇者

 期待する出力値
1

解答

<?php
// 標準入力から1行取得し値があればループ
while($input = fgets(STDIN)){
    // ★if文の前にtrimしておくのがポイント
    $input = trim($input);
    if($input == "勇者"){
        $array[] = $input;
    }
}
echo count($array);
?>


次は配列を使ったランダムなくじ引きの作成方法に取り組む。
標準入力から参加者を読み込み、ランダムで人を選出する、ランダムくじ引き。
参加人数が変わっても対応できるやり方を習得する。




 演習「おみくじを作ろう」
標準入力でカンマ区切りのおみくじ結果データが入力されます。(例:大吉,吉,凶)
入力された結果を配列に代入し、その内容をランダムで出力する
プログラムを作成してください。
出力は配列尾内容をprint_rで出力し、その次の行でおみくじの結果を表示してください。

 入力される値
大吉,吉,凶

 期待する出力値
Array
(
[0] => 大吉
[1] => 吉
[2] => 凶
)
大吉

解答
<?php
// 標準入力から1行取得
$input = trim(fgets(STDIN));
// カンマで分割して配列に代入
$array = explode(",", $input);
// ランダムの上限値を計算して変数に代入
$max = count($input) - 1;
// 配列の中身を出力
print_r($array);
// ランダム出力
echo $array[rand(0, $max)];
?>



演習②「くじ引きを作ろう」
標準入力で行数不明の複数行のおみくじ結果データが入力されます。
標準入力の空行も含む全ての行の値を配列に代入し、
その内容をランダムで出力するプログラムを作成してください。
出力は配列内容をprint_rで出力し、その次の行でおみくじの結果を表示してください。

 入力される値
大吉



 期待する出力値
Array
(
[0] => 大吉
[1] => 吉
[2] => 凶
)
大吉



模範解答
<?php
// 標準入力から1行取得し値があればループ
while($input = fgets(STDIN)){
    $array[] = trim($input);
}
// ランダムの上限値を計算して変数に代入
$max_num = count($array)-1;
// 配列の中身を出力
print_r($array);
// ランダム出力
$rand_num = rand(0,$max_num);
echo $array[$rand_num];
?>

解答2 どんくさい書き方
<?php
// 標準入力から1行取得
$input = trim(fgets(STDIN));
値があればループ
while($input){
    $array[] = $input;
    $input = trim(fgets(STDIN));
}
// ランダムの上限値を計算して変数に代入
$max_num = count($array)-1;
// 配列の中身を出力
print_r($array);
// ランダム出力
$rand_num = rand(0,$max_num);
echo $array[$rand_num];
?>

解答3 可読性を維持しつつ短めに書いた場合
<?php
// 標準入力から1行取得し値があればループ
while($input = fgets(STDIN)){
    $array[] = trim($input);
}
// 配列の中身を出力
print_r($array);
// ランダム出力
$rand_num = rand(0,count($array)-1);
echo $array[$rand_num];
?>



ランダムくじ引きの要点図解補足
https://paiza.jp/works/php/primer/beginner4/2128



ここまでを総括すると、これまで学習してきたことが有機的に結びついて
少しずつ高度になってきたがイマイチなじめていない表現も散見される。
しっかりと構文や関数を頭に入れた上で、ゼロからプログラムできるようにしたい。

次回一通り復習の上、paiza上の演習で未解答となったままの問題を解き
そのあと、連想配列やforeach、ソートを学習してPHP入門完了とする。





コメント

このブログの人気の投稿

PHP学習 ③

LINEスタンプ⑦