PHPの配列ソートで、便利に使える"array_multisort"なのだが、ソート後の処理で発生した不具合を経験したので、その内容と対策を備忘録しておきます。
ちなみに、これまで手作業でソート作業していて、この関数を知ってから書いたブログは以下のURLです。
array_multisortとはなんぞや???という方は、事前に読んでみてください。
[PHP] 連想配列のソートで便利に使える”array_multisort”
[PHP] 連想配列のソートで便利に使える"array_multisort"
サンプルコード
<?php
$data = array(
array(
"id" => 1,
"value" => "Sunday",
"pv" => 1000
),
array(
"id" => 2,
"value" => "Monday",
"pv" => 900
),
array(
"id" => 3,
"value" => "Tuesday",
"pv" => 800
),
array(
"id" => 4,
"value" => "Wednesday",
"pv" => 1500
),
array(
"id" => 5,
"value" => "Thersday",
"pv" => 1200
),
array(
"id" => 6,
"value" => "Fryday",
"pv" => 500
),
array(
"id" => 7,
"value" => "Saturday",
"pv" => 700
)
);
$pvs = array();
foreach($data as $key => $val){
array_push($pvs,$val["pv"]);
}
array_multisort($pvs , SORT_ASC , SORT_NUMERIC , $data);
print_r($data);
$ php array_multisort.php
Array
(
[0] => Array
(
[id] => 6
[value] => Fryday
[pv] => 500
)
[1] => Array
(
[id] => 7
[value] => Saturday
[pv] => 700
)
[2] => Array
(
[id] => 3
[value] => Tuesday
[pv] => 800
)
[3] => Array
(
[id] => 2
[value] => Monday
[pv] => 900
)
[4] => Array
(
[id] => 1
[value] => Sunday
[pv] => 1000
)
[5] => Array
(
[id] => 5
[value] => Thersday
[pv] => 1200
)
[6] => Array
(
[id] => 4
[value] => Wednesday
[pv] => 1500
)
)
このサンプルプログラムで、問題なく多重連想配列を操作できるのですが、本来の配列変数を上書きされてしまうのと、わざわざソートしたい対象keyの値を抽出するのがめんどくさいですね。
そこで、もっといい方法がリファレンスページに掲載されていました。
リファレンスページに掲載されていたarray_msort関数が、かなり便利な件
PHPマニュアル「array_multisort」
https://www.php.net/manual/ja/function.array-multisort.php#91638
このページに書かれている以下の関数を実行すると、key値を指定するだけという、非常に簡単な操作でmultisortが実行できます。
function array_msort($array, $cols)
{
$colarr = array();
foreach ($cols as $col => $order) {
$colarr[$col] = array();
foreach ($array as $k => $row) { $colarr[$col]['_'.$k] = strtolower($row[$col]); }
}
$eval = 'array_multisort(';
foreach ($cols as $col => $order) {
$eval .= '$colarr[\''.$col.'\'],'.$order.',';
}
$eval = substr($eval,0,-1).');';
eval($eval);
$ret = array();
foreach ($colarr as $col => $arr) {
foreach ($arr as $k => $v) {
$k = substr($k,1);
if (!isset($ret[$k])) $ret[$k] = $array[$k];
$ret[$k][$col] = $array[$k][$col];
}
}
return $ret;
}
これをPHPに搭載して、下記のように実行します。
$data2 = array_msort($data , array("pv"=>SORT_ASC));
print_r($data2);
php array_multisort.php
Array
(
[5] => Array
(
[id] => 6
[value] => Fryday
[pv] => 500
)
[6] => Array
(
[id] => 7
[value] => Saturday
[pv] => 700
)
[2] => Array
(
[id] => 3
[value] => Tuesday
[pv] => 800
)
[1] => Array
(
[id] => 2
[value] => Monday
[pv] => 900
)
[0] => Array
(
[id] => 1
[value] => Sunday
[pv] => 1000
)
[4] => Array
(
[id] => 5
[value] => Thersday
[pv] => 1200
)
[3] => Array
(
[id] => 4
[value] => Wednesday
[pv] => 1500
)
)
とてもサックリと、実行結果を得ることができます。
非常にいい関数ですね。
トラブルポイントと解決方法
ネイティブ関数のarray_multisortと、追加のarray_msortの結果を比べてみると、違う点に気がつきませんか?
結果のトップレベル配列順番の数値が、array_msortの場合は変換前のモノを保持している点です。
これは、元配列にすぐに戻すことも可能だし、ソート変換した状態も保持してくれているので、非常に便利な状態ですが、このデータの取り出し方に注意しなければいけません。
トラブルの元になる得る原因は、この連想配列からデータを取り出す時に、for文で取り出すかforeachで取り出すかで、順番が変わってくるので、その点要注意です。
for
forで取り出すと、トップレベル配列順番の数値通りになるので、元の順番をキープした結果になり、
foreach
foreachの場合は、変換後(ソート実行後)の順番で取り出すことができるようになります。
ケースバーケースで、どちらかを使って行うのが良さそうです。
何も知らずにfor文だけを使って、ソートされていないと騒がないように気をつけましょう。
改めてarray_multisortはソートー便利 !!
0 件のコメント:
コメントを投稿