[PHP]配列の重複した値を値別にまとめる 自作関数array_collect_values()

Read More




先日の記事の続きとなる。

■先日の記事:[PHP]配列の重複した値をカウントするarray_count_values()
http://xirasaya.com/?m=detail&hid=471



配列の重複した値をカウントするのではなく、
配列の重複した値を値別にまとめる方が色々と使いやすいんじゃないかと思った。


まあ言葉では若干伝わりにくいと思うので例を挙げる。


■配列のサンプル
$ary = array(
  'key1'=>'hoge',
  'key2'=>'piyo',
  'key3'=>'piyo',
  'key4'=>'fuga',
  'key5'=>'fuga',
  'key6'=>'fuga'
);



これをarray_count_values()に渡すと以下のような結果が返ってくる。

■重複した値をカウント
array (
  'hoge' => 1,
  'piyo' => 2,
  'fuga' => 3,
)


この例だとpiyoちゃんは2個あるのがわかる。
だがこれだけでは元配列のどの要素だか特定できない。



そこで自作関数array_collect_values()の登場。
重複した値のカウントではなく、要素を特定するためのキーを配列で持たせた。

その結果は以下のようになる。

■重複した値がまとまる
array (
  'hoge' => 
  array (
    0 => 'key1',
  ),
  'piyo' => 
  array (
    0 => 'key2',
    1 => 'key3',
  ),
  'fuga' => 
  array (
    0 => 'key4',
    1 => 'key5',
    2 => 'key6',
  ),
)


これでpiyoちゃんのキーはkey2key3だということがわかる。

値のカウントが欲しいならpiyoをcount()することで2という数値もとれる。
この数値はarray_count_values()を使って取得できる値と同じ。




--
さて、配列の重複した値を値別にまとめる自作関数array_collect_values()は以下の通り。


■配列の重複した値を値別にまとめるarray_collect_values()
/**
 * 配列の重複した値を値別にまとめる
 * 
 * @param array $ary=array()
 * @param integer $sort=0  // SORT_ASC, SORT_DESC
 * @return array
 */
function array_collect_values($ary=array(), $sort=0)
{
  $ret = array();
  
  $res = array_count_values($ary);
  if(is_array($res))
  {
    foreach($ary as $key => $val)
    {
      if(array_key_exists($val, $res))
      {
        $ret[$val][] = $key;
      }
    }
    
    if($sort)
    {
      $temp=array();
      foreach($ret as $key => $val)
      {
        $temp[$key]  = count($val);
      }
      array_multisort($temp, $sort, $ret);
    }
  }
  
  return $ret;
}



第2引数を指定すると結果配列に対してソートをかけることができる。
PHP定数のSORT_ASCSORT_DESCが使える。

ただしデフォルトでは0(ソートしない)としている。
これはarray_count_values()の結果配列の並びと同じにしたかったから。


んでも実際に使っていくとわかるがソートは関数内でしなきゃとてもめんどくさい。
外でいちいちforeach()なんか回してられん。

ってことで第2引数にデフォルトでは使用していないソート機能が付いた。






--
あと厳密には「配列の重複した値を」ではなくて「配列に出現する値を」という表現が正しい。

だが重複した値を調べるのに利用することを想定しているので、
あえて「配列の重複した値を値別にまとめる」という方を使っている。

だから厳密にいうと本記事のタイトルは以下のが正しい。
×配列の重複した値を値別にまとめる
○配列に出現する値を値別にまとめる


あるいは、
○配列の要素を値別にまとめる
とか。



まあその辺は好きにして。






--
さらに余談だが、
最初、自作関数の名前はarray_duplicate_values()にしようかと思ってた。

でもよくよく考えるとそれだと意味が違ってくるので、
「まとめる」という方を強調してarray_collect_values()にしたという経緯がある。




ありそうな名前なのだが本日(2015/06/17現在)の時点では、array_collect_valuesでググった検索結果は…

なんと0




機能的には違ったとしても名前だけでいったらありそうなのに。

意外な結果にびっくりしてなんだかうれしくなってつい記念のSSをとってしまった。




仕事などで検索結果の順位を一度でも意識したことがある人ならきっとこの感覚はわかってくれると思う。