ShimakazeSoft Tech

Python好きの新卒WEBエンジニアが技術記事を執筆するブログ。主にWEB系や機械学習系のことを掲載。

PHPの配列で重複した値の数をカウントするアルゴリズム

php
PHPの配列で、値が格納された配列内で重複している要素の出現回数をカウントしてくれるアルゴリズムを紹介します。
PHPでは既にarray_count_valuesという関数が用意されており、この関数の引数に配列を指定すれば、

PHP: array_count_values - Manual

実際にarray_count_valuesを使用してみたサンプルです。

<?php
$input = array("orange","blue","php","hoge","php","apple","test","orange");
$output = array_count_values($input);
print_r($output);
?>

結果は以下のように出力されます。

Array
(
    [orange] => 1
    [blue] => 1
    [php] => 2
    [apple] => 1
    [test] => 1
)

JavaScriptで配列の重複している項目の数をカウントする
array_count_values以外にも上記URLを参考に、以下のようなPHPで独自に実装したコードもあります。

<?php
$counts = array();
$tmpArray = array("apple","hoge","php","hoge","php","apple","test","orange");
for($i = 0; $i < count($tmpArray); $i++){
    $key = $tmpArray[$i];
    $counts[$key] = (in_array($key, $tmpArray)) ? $counts[$key] + 1 : 1;
}
?>

以下も同じような結果を出力します。

Array
(
    [orange] => 1
    [blue] => 1
    [php] => 2
    [apple] => 1
    [test] => 1
)

上記二つのarray_count_valuesを使った方法とそうじゃない方法を使って実行時間を比べてみます。
まず最初に0~9の4桁の数値を1000個を乱数で生成します。数値一つ一つは文字列型に変換して配列に格納します。

「array_count_valuesを使った方法とそうじゃない方法」のそれぞれの処理を1000回繰り返し、合計時間と平均時間を出力して比べてみます。

<?php

$MAX = 1000;
function RandStr($length) {
    $str = array_merge(range('0', '9'));

    $r_str = null;
    for ($i = 0; $i < $length; $i++) {
        $r_str .= $str[rand(0, count($str) - 1)];
    }
    return $r_str;
}

$tmpArray = array();
for($i = 0; $i < $MAX; $i++){
    array_push($tmpArray, RandStr(4));
}

$time = 0;
$time_start = microtime(true);
for($i = 0; $i < 1000; $i++){
    $counts = array_count_values($tmpArray);
}
$time = (microtime(true) - $time_start);
echo "処理時間:".sprintf("%.20f", $time)."\n";

$time = $time/1000;
echo "処理時間:".sprintf("%.20f", $time)."\n";

echo "\n";


$time = 0;
$time_start = microtime(true);
for($d = 0; $d < 1000; $d++){
    $counts = array();
    for($i = 0; $i < count($tmpArray); $i++){
        $key = $tmpArray[$i];
        $counts[$key] = (in_array($key, $tmpArray)) ? $counts[$key] + 1 : 1;
    }
}
$time = (microtime(true) - $time_start);
echo "処理時間:".sprintf("%.20f", $time)."\n";

$time = $time/1000;
echo "処理時間:".sprintf("%.20f", $time)."\n";
?>


上記処理を自分の環境で実行したところ、実行処理時間は以下のようになりました。(PHP7.1の環境で試しました。)

//array_count_valuesを使った処理
合計時間:0.02799391746520996094秒
平均時間:0.00002799391746520996秒

//array_count_valuesを使わなかった処理
合計時間:18.34730386734008789062秒
平均時間:0.01834730386734008747秒

array_count_valuesを使ったほうが断然早いことがわかります。array_count_valuesで使われているアルゴリズムが、どんな実装されているかは今度見てみようと思います。