php 二維陣列排序

soledad發表於2019-02-16

前提

給定一個二維陣列,請根據指定的陣列key,寫出最優的排序。排序條件age asc,sex desc,指定陣列如下:

$arr = [
            [`id`=>1, `age`=>1, `sex`=>6, `name`=>`a`],
            [`id`=>2, `age`=>3, `sex`=>1, `name`=>`c`],
            [`id`=>3, `age`=>3, `sex`=>1, `name`=>`b`],
            [`id`=>4, `age`=>2, `sex`=>1, `name`=>`d`],
        ];

估計大家都沒有什麼問題,排序嘛,簡單的不要不要的:

方式一:

 array_multisort(array_column($arr,`age`),SORT_ASC,array_column($arr,`sex`), SORT_DESC, $mylist);

這應該是最簡單的方式了,直接使用php現成的函式,快捷的不要不要的。

方式二:

 $sort = [];
        foreach($arr as $k=>$v) {
          
            $sort[`age`][$k] = $v[`age`];
            $sort[`sex`][$k] = $v[`sex`];
        }

array_multisort($sort[`age`],SORT_ASC,$sort[`sex`],SORT_DESC,$mylist);

嗯,勉強看的過去,但是感覺有點不優雅。

方式三:


        $orders=[`age`=>`asc`,`sex`=>`desc`];
        usort($arr, function($a, $b) use($orders) {
            $result = [];
            foreach ($orders as $key=>$value) {
                list($field, $sort) = [$key,$value];
                if (!(isset($a[$field]) && isset($b[$field]))) {
                    continue;
                }
                if (strcasecmp($sort, `desc`) === 0) {
                    $tmp = $a;
                    $a = $b;
                    $b = $tmp;
                }
                if (is_numeric($a[$field]) && is_numeric($b[$field]) ) {
                    $result[] = $a[$field] - $b[$field];
                } else {
                    $result[] = strcmp($a[$field], $b[$field]);
                }
            }

            return implode(``, $result);
        });

三種方式都可以,都比較簡單,那麼問題來了。

問題

如果排序陣列不是固定的呢,排序陣列是動態從資料庫查詢出來,排序條件也不是固定的呢,那麼我們肯定要封裝函式,如果使用php內建函式:

function _sort(){
......
array_multisort(...)
}

這裡我們就看出問題來了,array_multisort的引數不固定啊,使用有兩個方法:func_get_args()...$arg,放棄func_get_args(),因為沒有辦法使用。如果是自己寫的函式也建議不用,因為使用func_get_args(),容易讓函式看上去是不需要傳遞引數的。如果你在寫大量程式碼的時候,進行縮放的時候,也很難了解這個函式引數大概細節。這是非常不方便的。所以函式如下:

function _sort( &$arr, $sorts )
        {
            $sortParams = [];
            foreach ( $sorts as $key => $v ) {
                $sortParams[] = array_column($arr, $key);
                $sortParams[] = strcasecmp($v, `desc`) === 0 ? SORT_DESC : SORT_ASC;
            }
            array_push($sortParams, $arr);
          
            array_multisort(...$sortParams);
        }
 



_sort([`age`=>`asc`,`name`=>`desc`,`sex`=>`asc`]);

看是去很好對吧,但是執行才知道,沒有效果,難道是array_multisort不支援...$arg,檢視了手冊,沒看到說明,?,那就放棄自帶的函式,想自己寫好了:


        function arrayOrderBy(array &$arr, $order = null) {
            if (is_null($order)) {
                return $arr;
            }
            $orders = explode(`,`, $order);

            usort($arr, function($a, $b) use($orders) {
                $result = array();

                foreach ($orders as $value) {
                    list($field, $sort) = array_map(`trim`, explode(` `, trim($value)));
                    if (!(isset($a[$field]) && isset($b[$field]))) {
                        continue;
                    }
                    if (strcasecmp($sort, `desc`) === 0) {
                        $tmp = $a;
                        $a = $b;
                        $b = $tmp;
                    }
                    if (is_numeric($a[$field]) && is_numeric($b[$field]) ) {
                        $result[] = $a[$field] - $b[$field];
                    } else {
                        $result[] = strcmp($a[$field], $b[$field]);
                    }
                }


arrayOrderBy($arr, `age asc,sex asc,name desc`);

其實這就是一道面試題,大概意思讓用PHP寫一個類似mysqlorder by的功能,其實也很簡單。

參考

https://stackoverflow.com/que…

相關文章