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

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

ただいまの
回答率

91.02%

  • PHP

    17714questions

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

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

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 302

yuus2733

score 101

<?php
    $input = "white yellow blue blue yellow blue";
    $array = explode(" " , $input);
    $count = array_count_values($array);

foreach($count as $key => $value){
  echo $key;
  echo " ".$value."\n";
}
?>
アウトプット結果
white 1
yellow 2
blue 3


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

追記

while($input){
    $key_value = explode(" ", $input);
    $key = $key_value;
    $value = count($key_value);
    $a[$key] = $value;
}


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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • kei344

    2017/11/11 19:18

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

    キャンセル

  • yuus2733

    2017/11/11 19:27

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

    キャンセル

回答 4

checkベストアンサー

+5

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

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

<?php
$input1 = [
    0 => "white",
    1 => "yellow",
    2 => "blue",
    3 => "blue",
    4 => "yellow",
    5 => "blue",
];
$input2 = [
    0 => "white",
    1 => "yellow",
    2 => "blue",
    1 => "red",
    0 => "green",
    5 => "blue",
];

function acv(array $arr): array
{
    $result = [];
    foreach ($arr as $key => $value) {
        $result[$value] = isset($result[$value]) ? $result[$value] + 1 : 1;
    }

    return $result;
}

var_dump(array_count_values($input1) === acv($input1));// true
var_dump(array_count_values($input2) === acv($input2));// true

(追記)

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

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

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

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

<?php
$input = "white yellow blue blue yellow blue";
$key_value = explode(" ", $input);
$result = [];
$i = 0;

while ($i < count($key_value)) {
    $key = $key_value[$i];
    $value = isset($result[$key]) ? $result[$key] + 1 : 1;
    $result[$key] = $value;
    $i++;
}

var_dump($result === array_count_values($key_value));// true

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/12 20:59 編集

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

    キャンセル

+4

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

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

while($input){
    $key_value = explode(" ", $input);
    $key = $key_value;
    $value = count($key_value);
    $a[$key] = $value;
}

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

今回のケースだと、

  1. 配列を取得する
  2. 配列を処理する(同じ要素の数をカウントする)
  3. カウントした処理を表示する

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

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

//inputを配列にする
    $input = "white yellow blue blue yellow blue";
    $array = explode(" " , $input);
//配列を処理する(同じ要素の数をカウントする)
    $count = array_count_values($array);

//カウントした処理を表示する
foreach($count as $key => $value){
  echo $key;
  echo " ".$value."\n";
}

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

//inputを配列にする
    $input = "white yellow blue blue yellow blue";
    $array = explode(" " , $input);
//配列を処理する(同じ要素の数をカウントする)
    $count = my_array_count_values($array);

//カウントした処理を表示する
foreach($count as $key => $value){
  echo $key;
  echo " ".$value."\n";
}

function my_array_count_values($array){
//ここに処理を書く
}

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

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

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

//inputを配列にする
    $input = "white yellow blue blue yellow blue";
    $array = explode(" " , $input);
//配列を処理する(同じ要素の数をカウントする)
    //どんなインプットがあるか確認をする
    var_dump($array)
    $count = array_count_values($array);
    //どんなアウトプットがあるか確認する
    var_dump($count);

//カウントした処理を表示する
foreach($count as $key => $value){
  echo $key;
  echo " ".$value."\n";
}

function my_array_count_values($array){
//ここに処理を書く
}

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

//inputを配列にする
    $input = "white yellow blue blue yellow blue";
    $array = explode(" " , $input);
//配列を処理する(同じ要素の数をカウントする)
    //どんなインプットがあるか確認をする
    var_dump($array)
    $count = my_array_count_values($array);
    //どんなアウトプットがあるか確認する。元のソースと同じになればOK
    var_dump($count);

//カウントした処理を表示する
foreach($count as $key => $value){
  echo $key;
  echo " ".$value."\n";
}

//引数は単純な配列
function my_array_count_values($array){
//ここに処理を書く

}

ここまで来て、初めて処理の内容を考えることになります。
my_array_count_values()に期待される処理内容としては

  1. 配列を受け取る
  2. 受け取った配列をループで回す
  3. ループの中で、同じ値があったら登場した回数を記録する
  4. ループの中での回数の記録は戻り値の形式で行う(値をキーとし、回数を値とする連想配列)
  5. 連想配列を返す

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

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

//連想配列を返す
    return $result;

}

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

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

//引数は単純な配列
 //**引数と戻り値の型指定は出来る環境(両方出来るのはPHP7以降)ならした方が確実に良い方法でが、ここでは省略しています**
function my_array_count_values($array){
//配列を受け取る($arrayで受け取っているので関数内には書く必要が無い)
//受け取った配列をループで回す
  //ループの中で連想配列を作る予定なので、$resultはそれより前で定義する必要がありそう
  $result = [];

    foreach($array as $value){
       //ループの中で、同じ値があったら登場した回数を記録する
       //ループの中での回数の記録は戻り値の形式で行う(値をキーとし、回数を値とする連想配列)
    }

//連想配列を返す
    return $result;

}

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

//引数は単純な配列
 //**引数と戻り値の型指定は出来る環境(両方出来るのはPHP7以降)ならした方が確実に良い方法でが、ここでは省略しています**
function my_array_count_values($array){
//配列を受け取る($arrayで受け取っているので関数内には書く必要が無い)
//受け取った配列をループで回す
  //ループの中で連想配列を作る予定なので、$resultはそれより前で定義する必要がありそう
  $result = [];

    foreach($array as $value){
       //ループの中で、同じ値があったら登場した回数を記録する
           //「ループの中=返したい連想配列を作っている最中なので、作成中の連想配列にキーがあるかをチェックする
           if($result[$valu]){
              //このifの中で「登場した回数を記録する」を実装する
           }
       //ループの中での回数の記録は戻り値の形式で行う(値をキーとし、回数を値とする連想配列)
    }

//連想配列を返す
    return $result;

}

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

//引数は単純な配列
 //**引数と戻り値の型指定は出来る環境(両方出来るのはPHP7以降)ならした方が確実に良い方法でが、ここでは省略しています**
function my_array_count_values($array){
//配列を受け取る($arrayで受け取っているので関数内には書く必要が無い)
//受け取った配列をループで回す
  //ループの中で連想配列を作る予定なので、$resultはそれより前で定義する必要がありそう
  $result = [];

    foreach($array as $value){
       //ループの中で、同じ値があったら登場した回数を記録する
           //「ループの中=返したい連想配列を作っている最中なので、作成中の連想配列にキーがあるかをチェックする
           if(isset($result[$value])){
              //このifの中で「登場した回数を記録する」を実装する
                //ループの中での回数の記録は戻り値の形式で行う(値をキーとし、回数を値とする連想配列
                $result[$value] = $result[$value] + 1;

           }else{
                $result[$value] = 1;
           }
    }

//連想配列を返す
    return $result;

}

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/12 20:40

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

    キャンセル

+3

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

  $input = "white yellow blue blue yellow blue";
  $array = explode(" " , $input);

  $count = [];
  foreach ($array as $key) {
    if (! array_key_exists($key, $count)) { // キー $key がまだなければ
      // まだ $count[$key] が存在しない場合の処理
    } else {
      // 既に $count[$key] が存在する場合の処理
    }
    print_r($count); // デバッグ用出力
  }

【実行結果】
Array
(
    [white] => 1
)
Array
(
    [white] => 1
    [yellow] => 1
)
Array
(
    [white] => 1
    [yellow] => 1
    [blue] => 1
)
Array
(
    [white] => 1
    [yellow] => 1
    [blue] => 2
)
Array
(
    [white] => 1
    [yellow] => 2
    [blue] => 2
)
Array
(
    [white] => 1
    [yellow] => 2
    [blue] => 3
)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/12 20: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で何かする必要はありますか?

    キャンセル

+1

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

<?PHP
$input = "white yellow blue blue yellow blue";
$a = [];

foreach(explode(" " , $input) as $val){
  if(count($b=array_filter($a,function($x) use($val){
    return $x["color"]==$val;
  }))==0){
    $a[]=["color"=>$val,"count"=>1];
  }else{
    $a[array_keys($b)[0]]["count"]++;
  }
};
print_r($a);

foreach($a as $val){
  print $val["color"].":".$val["count"]."<br>\n";
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/13 15:21

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

    キャンセル

  • 2017/11/13 15:27 編集

    print_r($a)のところで示しているように

    $a=[
    ["color"=>"white", "count"=>1],
    ["color"=>"yellow","count"=>2],
    ["color"=>"blue", "count"=>3],
    ];

    というデータで保持するということです。
    他の回答にあるように色自体をキーにする方法もありますが
    上記であればソートをしたり別の属性をつけたりするのも管理が楽になります

    キャンセル

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

  • ただいまの回答率 91.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • PHP

    17714questions

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