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

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

新規登録して質問してみよう
ただいま回答率
85.50%
PHP

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

Q&A

解決済

4回答

1803閲覧

関数に頼り切りにならないコーディングができるようになりたい

退会済みユーザー

退会済みユーザー

総合スコア0

PHP

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

0グッド

1クリップ

投稿2017/11/11 10:14

編集2017/11/11 12:03

php

1<?php 2 $input = "white yellow blue blue yellow blue"; 3 $array = explode(" " , $input); 4 $count = array_count_values($array); 5 6foreach($count as $key => $value){ 7 echo $key; 8 echo " ".$value."\n"; 9} 10?> 11アウトプット結果 12white 1 13yellow 2 14blue 3

というコードを他のサイトを参考に書いてみたのですが、
array_count_valueを使用した部分を関数なしで書いた場合どのようになるかご教示いただけないでしょうか。
取得した値をkeyにいれなおし、出現回数をvalueにいれたいのですが、
PHPの連想配列のkeyに重複する物があった場合valueとともに上書きされてしまうという
仕様を読んで、どうすればいいかわからなくなってしまいました。
できましたら答えだけじゃなくどういう書籍やサイトで勉強をされたかも教えていただけたら嬉しいです。
また、先程の記事も見てくださった方がいらっしゃいましたら再びで申し訳ないですがよろしくお願いします。

追記

php

1while($input){ 2 $key_value = explode(" ", $input); 3 $key = $key_value; 4 $value = count($key_value); 5 $a[$key] = $value; 6}

先に作ってある$inputの中身の空白を取りながら色をわけてkeyにいれる、そのkeyのvalueには
カウントした数を入れたいのですが、上記のように書くと入力がそもそも一行だからループになっていない、keyに色名とvalueにそれぞれの色の出現回数をいれたいのにそれも出来てないと言った状況で、whileを使うこと自体が間違いだと思っています。
知っていることが少なく適切な使い方もできていません。どうすればいいでしょうか。

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

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

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

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

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

kei344

2017/11/11 10:18

ご自身で試されたコードを質問文に追記し、「何」が「どのように」わからないのか、コードのどの部分で詰まっているのかなどを具体的に追記されたほうが回答が望めると思います。
退会済みユーザー

退会済みユーザー

2017/11/11 10:27

色々ごちゃごちゃやりすぎて混乱してしまったので、しばらく時間かかると思います、すみません。
guest

回答4

0

ベストアンサー

array_count_valueを使用した部分を関数なしで書いた場合どのようになるか

的外れかもしれませんが、以下のように行えると思います。

PHP

1<?php 2$input1 = [ 3 0 => "white", 4 1 => "yellow", 5 2 => "blue", 6 3 => "blue", 7 4 => "yellow", 8 5 => "blue", 9]; 10$input2 = [ 11 0 => "white", 12 1 => "yellow", 13 2 => "blue", 14 1 => "red", 15 0 => "green", 16 5 => "blue", 17]; 18 19function acv(array $arr): array 20{ 21 $result = []; 22 foreach ($arr as $key => $value) { 23 $result[$value] = isset($result[$value]) ? $result[$value] + 1 : 1; 24 } 25 26 return $result; 27} 28 29var_dump(array_count_values($input1) === acv($input1));// true 30var_dump(array_count_values($input2) === acv($input2));// true

(追記)

入力がそもそも一行だからループになっていない

whileループの前で予めexplodeで分割しておくことで解決できます。

keyに色名とvalueにそれぞれの色の出現回数をいれたいのにそれも出来てない

結果を入れておく配列内にその色名のキーが存在するかどうかを調べて、ある場合はその要素の値に1を足し、無ければ1を代入するようにすれば、キー名を色の名前にして値をその色の出現回数にすることができると思います。

PHP

1<?php 2$input = "white yellow blue blue yellow blue"; 3$key_value = explode(" ", $input); 4$result = []; 5$i = 0; 6 7while ($i < count($key_value)) { 8 $key = $key_value[$i]; 9 $value = isset($result[$key]) ? $result[$key] + 1 : 1; 10 $result[$key] = $value; 11 $i++; 12} 13 14var_dump($result === array_count_values($key_value));// true

投稿2017/11/11 11:11

編集2017/11/11 12:41
s8_chu

総合スコア14731

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

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

退会済みユーザー

退会済みユーザー

2017/11/12 11:59 編集

早い回答ありがとうございます。 ? :など演算子の意味・仕様・扱い方を疎かにしていました・・・しっかり把握できるようにがんばります。
guest

0

具体的なコードはs8_chu様の回答で例示されているので、アプローチの方法を回答してみます。
途中のソースにエラーがあったらごめんなさい(最終的なソースはs8_chu様の回答のものになるので、途中の考え方を追ってもらえればそれで良いと思います)

考え方については、出来るだけ基礎が掲載されている教科書的な書籍好き嫌いはあるかもですが、例えばこういう書籍 を手に取って一つ一つ進めていくか、とにかく実践的な書籍で実際にコードを大量に書いて覚えるかのどちらかのうち、ご自身に合った方法をお勧めします。

PHP

1while($input){ 2 $key_value = explode(" ", $input); 3 $key = $key_value; 4 $value = count($key_value); 5 $a[$key] = $value; 6}

についてはやりたいこと整理出来ないまま詰め込み過ぎて失敗しているように見えます。
まずは日本語でやりたいことを整理して、コメントから先に書いてみることをお勧めします。

今回のケースだと、
0. 配列を取得する
0. 配列を処理する(同じ要素の数をカウントする)
0. カウントした処理を表示する

という処理が元々のarray_count_valuesを使ったソースに書かれています。

ソースにするとこんな感じで

PHP

1//inputを配列にする 2 $input = "white yellow blue blue yellow blue"; 3 $array = explode(" " , $input); 4//配列を処理する(同じ要素の数をカウントする) 5 $count = array_count_values($array); 6 7//カウントした処理を表示する 8foreach($count as $key => $value){ 9 echo $key; 10 echo " ".$value."\n"; 11} 12

とコメントを付けることが出来ます。
今回のケースでやりたいことは
array_count_values()を自力で書いてみる
なので、他の部分は欲張らずに、「array_count_values()だけ書き換える」ことを目指しましょう。
array_count_values()は関数なので、別の名前の関数(my_array_count_valuesとしました)を自作して、インプット(引数)とアウトプット(戻り値)を再現すれば他の部分は変えなくていいはず(変えてはいけない)です。

PHP

1//inputを配列にする 2 $input = "white yellow blue blue yellow blue"; 3 $array = explode(" " , $input); 4//配列を処理する(同じ要素の数をカウントする) 5 $count = my_array_count_values($array); 6 7//カウントした処理を表示する 8foreach($count as $key => $value){ 9 echo $key; 10 echo " ".$value."\n"; 11} 12 13function my_array_count_values($array){ 14//ここに処理を書く 15} 16

次に、my_array_count_values()の中身を考えるわけですが、
使う側からすると関数の内部で何をしているかは関係ないので、
まずはインプットとアウトプットを定義します。
定義と言っても、元からある関数を再現したいので、
PHPマニュアル http://php.net/manual/ja/function.array-count-values.php
を見て、何を引き受けて何を返せばいいのかを確認します。

引数が
「配列(同じ値が複数あるかもしれないし、一つだけかもしれない。)」で
「返り値が登場する値をキーとし、回数を値とした連想配列」であることが確認出来ます。

ただ、なかなか直感的に理解するのは大変なので、実際に動いているソースで確認するのが楽です。
(var_dumpより適切な方法がありますが、学習段階では環境を問わないvar_dumpでも良いと思います)

PHP

1//inputを配列にする 2 $input = "white yellow blue blue yellow blue"; 3 $array = explode(" " , $input); 4//配列を処理する(同じ要素の数をカウントする) 5 //どんなインプットがあるか確認をする 6 var_dump($array) 7 $count = array_count_values($array); 8 //どんなアウトプットがあるか確認する 9 var_dump($count); 10 11//カウントした処理を表示する 12foreach($count as $key => $value){ 13 echo $key; 14 echo " ".$value."\n"; 15} 16 17function my_array_count_values($array){ 18//ここに処理を書く 19} 20

上記ソースで取得されるインプットを渡したときに
アウトプットとして同じものが自作関数から帰ってくれば、処理としては再現できているだろうと判断できるわけです。

PHP

1//inputを配列にする 2 $input = "white yellow blue blue yellow blue"; 3 $array = explode(" " , $input); 4//配列を処理する(同じ要素の数をカウントする) 5 //どんなインプットがあるか確認をする 6 var_dump($array) 7 $count = my_array_count_values($array); 8 //どんなアウトプットがあるか確認する。元のソースと同じになればOK 9 var_dump($count); 10 11//カウントした処理を表示する 12foreach($count as $key => $value){ 13 echo $key; 14 echo " ".$value."\n"; 15} 16 17//引数は単純な配列 18function my_array_count_values($array){ 19//ここに処理を書く 20 21} 22

ここまで来て、初めて処理の内容を考えることになります。
my_array_count_values()に期待される処理内容としては
0. 配列を受け取る
0. 受け取った配列をループで回す
0. ループの中で、同じ値があったら登場した回数を記録する
0. ループの中での回数の記録は戻り値の形式で行う(値をキーとし、回数を値とする連想配列)
0. 連想配列を返す

という感じです。(完全再現するためには実際にはエラー処理などが必要ですが、本筋から離れそうなので省略します)
これもいきなり全部やると大変なので、まずは1と2、5を実装すると以下のようになります。

PHP

1//引数は単純な配列 2 //**引数と戻り値の型指定は出来る環境(両方出来るのはPHP7以降)ならした方が確実に良い方法でが、ここでは省略しています** 3function my_array_count_values($array){ 4//配列を受け取る($arrayで受け取っているので関数内には書く必要が無い) 5//受け取った配列をループで回す 6 foreach($array as $value){ 7 //ループの中で、同じ値があったら登場した回数を記録する 8 //ループの中での回数の記録は戻り値の形式で行う(値をキーとし、回数を値とする連想配列) 9 } 10 11//連想配列を返す 12 return $result; 13 14} 15

このままだと、$resultが未定義なので、ここから先は$resultを返したい形で用意するという事に集中します。

まずは$resultを定義する場所を考えて

PHP

1//引数は単純な配列 2 //**引数と戻り値の型指定は出来る環境(両方出来るのはPHP7以降)ならした方が確実に良い方法でが、ここでは省略しています** 3function my_array_count_values($array){ 4//配列を受け取る($arrayで受け取っているので関数内には書く必要が無い) 5//受け取った配列をループで回す 6 //ループの中で連想配列を作る予定なので、$resultはそれより前で定義する必要がありそう 7 $result = []; 8 9 foreach($array as $value){ 10 //ループの中で、同じ値があったら登場した回数を記録する 11 //ループの中での回数の記録は戻り値の形式で行う(値をキーとし、回数を値とする連想配列) 12 } 13 14//連想配列を返す 15 return $result; 16 17} 18

ループの中で、同じ値があったら登場した回数を記録する
の「同じ値があったら」はどうすれば検出出来るかを考えると、
「ループの中=返したい連想配列を作っている最中なので、作成中の連想配列にキーがあるかをチェックする」で検出が出来そうです

PHP

1//引数は単純な配列 2 //**引数と戻り値の型指定は出来る環境(両方出来るのはPHP7以降)ならした方が確実に良い方法でが、ここでは省略しています** 3function my_array_count_values($array){ 4//配列を受け取る($arrayで受け取っているので関数内には書く必要が無い) 5//受け取った配列をループで回す 6 //ループの中で連想配列を作る予定なので、$resultはそれより前で定義する必要がありそう 7 $result = []; 8 9 foreach($array as $value){ 10 //ループの中で、同じ値があったら登場した回数を記録する 11 //「ループの中=返したい連想配列を作っている最中なので、作成中の連想配列にキーがあるかをチェックする 12 if($result[$valu]){ 13 //このifの中で「登場した回数を記録する」を実装する 14 } 15 //ループの中での回数の記録は戻り値の形式で行う(値をキーとし、回数を値とする連想配列) 16 } 17 18//連想配列を返す 19 return $result; 20 21} 22

「同じ値があったら登場した回数を記録する」
は、前述の検出する部分で、作成途中の連想配列をチェックしているので、その値にプラス1すれば出来そうです。
初めて見かける値なら1を設定しましょう
「ループの中での回数の記録は戻り値の形式で行う(値をキーとし、回数を値とする連想配列」も一緒に出来てしまいました。

PHP

1//引数は単純な配列 2 //**引数と戻り値の型指定は出来る環境(両方出来るのはPHP7以降)ならした方が確実に良い方法でが、ここでは省略しています** 3function my_array_count_values($array){ 4//配列を受け取る($arrayで受け取っているので関数内には書く必要が無い) 5//受け取った配列をループで回す 6 //ループの中で連想配列を作る予定なので、$resultはそれより前で定義する必要がありそう 7 $result = []; 8 9 foreach($array as $value){ 10 //ループの中で、同じ値があったら登場した回数を記録する 11 //「ループの中=返したい連想配列を作っている最中なので、作成中の連想配列にキーがあるかをチェックする 12 if(isset($result[$value])){ 13 //このifの中で「登場した回数を記録する」を実装する 14 //ループの中での回数の記録は戻り値の形式で行う(値をキーとし、回数を値とする連想配列 15 $result[$value] = $result[$value] + 1; 16 17 }else{ 18 $result[$value] = 1; 19 } 20 } 21 22//連想配列を返す 23 return $result; 24 25} 26

という感じで処理は書けました。
あとは実行してみて、var_dumpの結果が同じか確認したり、出力された配列をarray_count_valuesで出力した配列と完全に同じか確認してみたりします。

その辺りのチェックやifの部分は今回のケースだと三項演算子を使った方がスマートだったり、PHPは最新版を使って引数や戻り値の型チェックは自動で行った方が確実で楽だよねという事を考えていくと、
s8_chu様の回答のソースコードが出来上がります。

投稿2017/11/11 13:49

編集2017/11/11 14:09
tanat

総合スコア18709

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

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

退会済みユーザー

退会済みユーザー

2017/11/12 11:40

いつもありがとうございます。 やさしいPHP、近くの書店と図書館で見た覚えがあるので今日再び見に行ってみました。書店では売れてしまった(記憶違いでもともとなかったかもしれません)、すぐ近くの図書館にもなかったのでひとまず同じ区内の図書館に借りに行くことになりそうです。
guest

0

スケルトンを書いて穴埋め式にしてみましたので考えてみてください

PHP

1 $input = "white yellow blue blue yellow blue"; 2 $array = explode(" " , $input); 3 4 $count = []; 5 foreach ($array as $key) { 6 if (! array_key_exists($key, $count)) { // キー $key がまだなければ 7 // まだ $count[$key] が存在しない場合の処理 8 } else { 9 // 既に $count[$key] が存在する場合の処理 10 } 11 print_r($count); // デバッグ用出力 12 } 13 14【実行結果】 15Array 16( 17 [white] => 1 18) 19Array 20( 21 [white] => 1 22 [yellow] => 1 23) 24Array 25( 26 [white] => 1 27 [yellow] => 1 28 [blue] => 1 29) 30Array 31( 32 [white] => 1 33 [yellow] => 1 34 [blue] => 2 35) 36Array 37( 38 [white] => 1 39 [yellow] => 2 40 [blue] => 2 41) 42Array 43( 44 [white] => 1 45 [yellow] => 2 46 [blue] => 3 47)

投稿2017/11/11 13:54

ockeghem

総合スコア11701

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

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

退会済みユーザー

退会済みユーザー

2017/11/12 11:39

<?php $input = "white yellow blue blue yellow blue"; $array = explode(" " , $input); $count = []; foreach ($array as $key) { if (! array_key_exists($key, $count)) { // キー $key がまだなければ // まだ $count[$key] が存在しない場合の処理 $count[$key] = count($count)+ 1; } else { // 既に $count[$key] が存在する場合の処理 } print_r($count); // デバッグ用出力 } ?> 遅くなり申し訳ないです。 こう書き加えたところ、ひとまず目的の動作になったようにみえるのですが、 elseで何かする必要はありますか?
guest

0

きちんとデータ管理したいならこんな感じ

PHP

1<?PHP 2$input = "white yellow blue blue yellow blue"; 3$a = []; 4 5foreach(explode(" " , $input) as $val){ 6 if(count($b=array_filter($a,function($x) use($val){ 7 return $x["color"]==$val; 8 }))==0){ 9 $a[]=["color"=>$val,"count"=>1]; 10 }else{ 11 $a[array_keys($b)[0]]["count"]++; 12 } 13}; 14print_r($a); 15 16foreach($a as $val){ 17 print $val["color"].":".$val["count"]."<br>\n"; 18}

投稿2017/11/13 03:06

yambejp

総合スコア114572

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

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

退会済みユーザー

退会済みユーザー

2017/11/13 06:21

ありがとうございます。 初めて見る書き方と動作の仕方で理解ができません・・・。 foreachのなかの書き方に名称などはついているのでしょうか?
yambejp

2017/11/13 06:27 編集

print_r($a)のところで示しているように $a=[ ["color"=>"white", "count"=>1], ["color"=>"yellow","count"=>2], ["color"=>"blue", "count"=>3], ]; というデータで保持するということです。 他の回答にあるように色自体をキーにする方法もありますが 上記であればソートをしたり別の属性をつけたりするのも管理が楽になります
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問