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

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

ただいまの
回答率

90.23%

PHP 配列の中に、指定した文字列が何回登場しているか?

受付中

回答 8

投稿

  • 評価
  • クリップ 6
  • VIEW 4,013

ckaposndbbba

score 205

こんにちは。
PHPで、「指定した配列の中で」「何個『PHP』という文字列があるかを知りたい」です。
たとえば、配列は以下のものだったとします。
$array = array(
   0 => array(
      "name" = "PHP",
      "description" = "PHPは、とっても面白い言語です。"
   ),
   1 => array(
      "name" = "javascript",
      "description" = "javascriptは、PHPと同じようなことをクライアントサイドで実行することができます。"
   ),
   2 => array(
      "name" = "PHPer",
      "description" = "PHPを書く人のことです。"
   )
);
それで、この配列の、nameキーの中に、PHPという文字列は何回登場しているか?という。
単に、PHPという文字列が何回...だったら、5回ですが、そうではなくて、
nameの中に入ってる値を対象に探したいんです。
そしたら、2回です。
意味わかりますかね。。

その、◯回という値を知りたいのですが、なにか方法はないでしょうか?
ちなみに、以下のコードとかも書いてみたりしたのですが
$kai = 0;
$count = count($array);
for($i = 0; $i < $count; $i++){
   if(stristr($array[$i]['name'],"PHP") !== false){
      $kai++;
   }
}
echo $kai . "回";
これだと、値が多いArrayを指定してしまうと、効率が悪くなってしまいます。
関数みたいなものは、あったりしますか?

わかりづらくてすみません。

よろしくお願いします。
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 8

+2

どのくらい大きい配列を想定してるか分かりませんが、
速度的にボトルネックになるくらいのサイズを扱わないといけない場合、
別レイヤーでなんとかするか(DBとか)拡張モジュール作るかで対応しますね。
まぁでも10万件ループするくらいでしたらそれほどかからないと思います。

誤差レベルですがforeach使ったほうが速いです。
キーのことを気にしなくてもいいメリットもあります。

$kai = 0;
foreach($array as $val){
   if(stristr($val['name'], "PHP") !== false){
      $kai++;
   }
}
echo $kai . "回\n";

私でしたら以下のように書きます。

$kai = count(array_filter($array, function($val){
    return stristr($val['name'], "PHP") !== false;
}));

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

>sounisi5011 さんへ

UTF-8はマルチバイト文字を含んでいようとstriposで十分です。
下記のようにマルチバイトの範囲の文字であってもASCIIの範囲に含まれないので、
strposやstr_replace、explodeもそのまま使えます。
ASCII ・・・ [0x00-0x7F]

UTF-8 2byte ・・・ [C0-DF][80-BF]
UTF-8 3byte ・・・ [E0-EF][80-BF][80-BF]
UTF-8 4byte ・・・ [F0-F7][80-BF][80-BF][80-BF]
UTF-8 5byte ・・・ [F8-FB][80-BF][80-BF][80-BF][80-BF]
UTF-8 6byte ・・・ [FC-FD][80-BF][80-BF][80-BF][80-BF][80-BF]

また、mb_~系の関数はかなり遅いので今回の質問の場合ボトルネックになる可能性もあります。
(対象とする文字列にもよりますが、strstrが1.5倍くらい遅いとすると10倍は遅いです)

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/03/23 15:17

    ちなみにですがShift-JISやEUC-JPなどのUTF-8以外の文字コードだとマルチバイトの文字コード中にASCIIのコードが現れるためmb_~系を使う必要があります。
    (UTF-8以外の文字コードを使うメリットはほとんどないと思っていますが・・・)

    キャンセル

  • 2015/03/24 18:05

    ありがとうございます。初めて知りました。

    キャンセル

0

手段の一つとして、事前にインデックスを作って置く方法もあります。

$idx = array(
    'PHP'   => array(0,2)  //"PHP"に該当するのは$array[0]と$array[2]
  , 'PHPer' => array(2)    //"PHPer"に該当するのは$array[2]
);

これであれば検索部分は以下のように最小限のループ回数ですみます。
if( array_key_exists('PHP', $idx) ){
    $key = $idx['PHP'];

    $len = count($key);
    for($i=0; $i<$len; $i++){
        // $array[ $key[$i] ] に対して処理
    }
}

最初にインデックスを作成するコストと、毎回検索するコストを比較して、適した方法を取捨選択されると良いかと思います。

ご参考まで。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

どのくらい軽減できるかはわかりませんが
var_dump( count( array_filter( $array, create_function( '$ary', 'return stripos( $ary["name"] ) !== false;' ) ) ) );

データベースとか、インデックスにするならセッターで数えておくとか、いっそインデックス含めたオブジェクトにするとか

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

そのような標準関数は無いと思います。
もしかしたら、公式ドキュメントの配列関数で探せば見つかるかもしれません。


提示されたコードにはまだ改善の余地があったため、以下に私が改善したコードを記載します。

$match_keyword='PHP';

$keyword_count=0;
foreach($array as $value){
    if(stripos($value['name'],$match_keyword) !== false){
        $keyword_count++;
    }
}

echo $keyword_count.'回';

  • 変数名を変更しました。
  • 検索する文字列を変数に入れ、扱いやすくしてみました。
  • 配列のループ処理はforeachで代用できるため、これに変更しました。
  • stristr()をstripos()に変更しました。

strstr()は、文字列の検出に適していません。
公式ドキュメントにも、以下のようにあります。

もし特定の haystack に needle があるかどうかを調べるだけの場合、 より高速でメモリ消費も少ない strpos() を代わりに使用してください。

公式ドキュメントの記述はこれのみですが、同じ理由でstristr()よりもstripos()が適していると考えました。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

print(count(preg_grep('/php/i',array_column($myarr,"name"))));

phpのバージョンが5.5未満であれば、array_columnが使えないので、以下の方法で実装する必要があります。
https://github.com/ramsey/array_column/blob/master/src/array_column.php

また、大文字小文字を区別するのであれば、正規表現を「/PHP/」にしてiオプションを外してください

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

関数の中で関数を呼べばいいかも

xmlを配列にする時参考にしたリンク
http://studio-key.com/157.html

ぶん投げで申し訳ないけど
後はガンバレ

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

-1

これだと、値が多いArrayを指定してしまうと、効率が悪くなってしまいます。 

はい。でも、仕方ないかな、と思います。それがArrayの宿命ですから。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/03/23 16:47

    なんかマイナスがついているな。まあ、いいけど。インデックスを使う等の手段があるのは知ったけど、それだと予め決められたキーワードについてしかインデックスできないし、そこまでやるなら全文検索系の機能のあるDBを使うことになりそうな。
    書き方を工夫して、コードを多少短くすることはできても、Arrayの要素数に比例して性能劣化するという性質は変わらないですよね。

    キャンセル

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

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