PHPには多くのソート関数がありますが、その中でも便利でありながら使い方がわかりにくいもののひとつであるarray_multisortとusortについて調べてみます。
http://jp2.php.net/array_multisort
マニュアルを見てみても
「複数の配列を一度に、 または、多次元の配列をその次元の一つでソートする際に使用可能です。 この関数は、ソートの際にキーの相関を維持します。」
としか書かれておらず、なんのこったという感じです。
日本語訳すると、引数の前のほうの配列をソートして、そのついでに引数の後ろのほうの配列も同じ順番でソートする、ということになります。
$a=array(3,5,1,4,2); $b=array('a','b','c','d','e'); array_multisort($a,$b); |
と書いた場合、
まず$aが普通にソートされて
$a=array(1,2,3,4,5);
となります。
それと同時に、$bが$aと同じ順番でソートされ、
$b=array('c','e','a','d','b');
となります。
さて、この関数をわかりにくくしている要因のひとつが引数の与え方です。
array_multisort($a,SORT_DESC,$b);
と書くと、$aが降順でソートされた上で$bがそれに従ってソートされます。
$a1=array(2,2,1,1,1); $a2=array(1,2,5,4,3); $b=array('a','b','c','d','e'); array_multisort($a1,$a2,$b); |
とすると、まず$a1がソートされ、$a2と$bがその順番に従ってソートされます。
更にその後、$a1の順番を壊さない範囲で$a2がソートされ、$bも$a2に従ってソートされます。
最終的に
$a1=array(1,1,1,2,2);
$a2=array(3,4,5,1,2);
$b=array('e','d','c','a','b');
となります。
更に引数を増やして
array_multisort($a1,$a2,SORT_STRING,$a3,$b);
などと書いても動作してしまうのが、便利さと同時にわかりにくさを感じる一因となっていることでしょう。
さて、array_multisortで便利なのが、多重配列のソートです。
以下のようなよくある商品データがあったとして、これを価格順にソートしたい場合。
$product=array( array('name'=>'みかん','price'=>'60'), array('name'=>'りんご','price'=>'180'), array('name'=>'バナナ','price'=>'48'), array('name'=>'いちご','price'=>'590'), array('name'=>'ぶどう','price'=>'298'), array('name'=>'ドリアン','price'=>'5000') ); |
必要なのは、ソート順を決定する配列と、ソート自体を行う配列です。
後者は出来てますので、前者を作ります。
foreach($product as $tmp){$sort_array[]=$tmp['price'];} |
これでソート用の配列$sort_array=array('60','180','48','590','298','5000')が出来ました。
array_multisort($sort_array,$product); |
めでたしめでたし。
さて、array_multisortにはソートオプションが用意されており、SORT_DESCで降順、SORT_STRINGで文字列順、SORT_NUMERICで数値順とソート順を変更することが出来ます。
しかし定義された順ではなく任意の順番でソートしたい場合、どうすればよいでしょう。
usortという、ユーザでソートオプション的なものを設定できる関数が用意されています。
二つの引数をとり、前のほうにしたい場合は-1を返し、後ろに並べるときは1を返す関数を作ってあげます。
とりあえずやってみましょう。
usort($product,'compare'); |
バナナを一番上に持って行きたかっただけなのですが、うまくいっていません。
バナナ以外の部分が出鱈目なことになってしまっています。
一体どういう基準でソートされたんだこれ?
どのサイトを見ても
return ($a['price'] < $b['price']) ? -1 : (($a['price'] > $b['price']) ? 1 : 0);
といったわざわざ定義する必要ないじゃん的ソート関数しか置いてないんですよね(ちなみに↑は昇順)
はてさて。