php排序 asort usort實例 對數組的多個字段排序 穩定排序

php中有很多排序函數,下面是常用的一些:
sort() 函數用於對數組單元從低到高進行排序。rsort() 函數用於對數組單元從高到低進行排序。asort() 函數用於對數組單元從低到高進行排序並保持索引關係。arsort() 函數用於對數組單元從高到低進行排序並保持索引關係。usort() 使用用戶自定義的比較函數對數組中的值進行排序uasort() 使用用戶自定義的比較函數對數組中的值進行排序並保持索引關聯

sort()用法很簡單,就不多說了。

接下來我們看一個案例:

有如下一個數組

$sorted_array = array(array('ts'=>3,'gold'=>4),
			array('ts'=>8,'gold'=>10),
			array('ts'=>5,'gold'=>7),
			array('ts'=>1,'gold'=>20),
			array('ts'=>9,'gold'=>7),
			array('ts'=>3,'gold'=>7)
		);

ts表示時間(戳),gold表示金幣。第一次的需求是按時間排序,時間新的排前面(ts越大表示越新)並保持其他數據不錯亂,即倒序排這個數組。下面先用arsort()來處理。如下函數的思路是,先將所有的ts的值保持次序不變加入到一個新的數組sa,然後倒序排這個sa並保持其索引關係,比如說排完之後ts=>9的就是sa的首個元素,但它是sa[5],其實就是按照排好後的次序得到了所有原$sorted_array的索引。依次加入新數組就能得到結果

print_r(sort_via_key($sorted_array, 'ts'));
function sort_via_key($data, $key)
{
	if(empty($data)) return array();
	$ret = array();
	$sorted_arr = array();
	foreach ($data as $i => $_item)	
	{
		$sorted_arr[$i] = $_item[$key];
	}
	arsort($sorted_arr);
	foreach ($sorted_arr as $i => $_item)
	{
		$ret[] = $data[$i];
	}
	return $ret;
}

結果輸出如下:

Array
(
    [0] => Array
        (
            [ts] => 9
            [gold] => 7
        )

    [1] => Array
        (
            [ts] => 8
            [gold] => 10
        )

    [2] => Array
        (
            [ts] => 5
            [gold] => 7
        )

    [3] => Array
        (
            [ts] => 3
            [gold] => 7
        )

    [4] => Array
        (
            [ts] => 3
            [gold] => 4
        )

    [5] => Array
        (
            [ts] => 1
            [gold] => 20
        )
)

OK,搞定。可是接下來又有了新的需求,首先按照gold來排,金幣多的排前面,金幣相同時才按時間來排。此時你也許會想這很簡單啊,我們已經有了排序的函數,剛纔用時間(ts)排了,接下來再用gold排一遍,不就好了嗎。

sort_via_key($sorted_array, 'gold')

好,我們來看看排完的結果:

Array
(
    [0] => Array
        (
            [ts] => 1
            [gold] => 20
        )

    [1] => Array
        (
            [ts] => 8
            [gold] => 10
        )

    [2] => Array
        (
            [ts] => 9
            [gold] => 7
        )

    [3] => Array
        (
            [ts] => 3
            [gold] => 7
        )

    [4] => Array
        (
            [ts] => 5
            [gold] => 7
        )

    [5] => Array
        (
            [ts] => 3
            [gold] => 4
        )
)


gold同時爲7的情況下,出問題了把。出現這個問題的原因在於arsort並不是一種穩定的排序,他把剛纔排好的順序打亂了。
接下來先說說usort。其實我們剛纔寫的sort_via_key函數,用usort很簡單就可以實現了。

usort的用法,php手冊裏有詳細說明:http://www.php.net/manual/zh/function.usort.php,簡單來說就是提供一個回調的比較函數,比較函數必須在第一個參數被認爲小於,等於或大於第二個參數時分別返回一個小於,等於或大於零的整數。

我們只需提供如下比較函數就能完成第一個需求:

usort($sorted_array, "cmp_ts_desc");
function cmp_ts_desc($a, $b)
{
    if ($a['ts'] == $b['ts']) {
        return 0;
    }
    return ($a['ts'] < $b['ts']) ? 1 : -1;	//倒序的話a<b返回大於0,正序a<b返回小於0
}

看上去簡單多了吧。
好,該是解決這個問題的時候了。我們可以提供一個這樣的函數

function multi_compare($a, $b)
{
	$criteria = array(
		'gold'=>'desc',
		'ts'=>'desc'	//這裏還可以根據需要繼續加條件 如:'x'=>'asc'等
	);
	foreach($criteria as $what => $order){
        if($a[$what] == $b[$what]){
            continue;
        }
        return (($order == 'desc')?-1:1) * (($a[$what] < $b[$what]) ? -1 : 1);
    }
    return 0;
}

此時只用

usort($sorted_array, "multi_compare");

就OK了,結果如下:

Array
(
    [0] => Array
        (
            [ts] => 1
            [gold] => 20
        )

    [1] => Array
        (
            [ts] => 8
            [gold] => 10
        )

    [2] => Array
        (
            [ts] => 9
            [gold] => 7
        )

    [3] => Array
        (
            [ts] => 5
            [gold] => 7
        )

    [4] => Array
        (
            [ts] => 3
            [gold] => 7
        )

    [5] => Array
        (
            [ts] => 3
            [gold] => 4
        )

)


這個函數正是精髓所在,即使你再多個需求多個key按照正序來排一樣可以滿足。仔細讀這個函數,其實就是闡述了一遍需求的內容,如果不同的話就按照$criteria[0]的標準來排序,如果相同,繼續$criteria[1]的標準來排序。如此輕鬆是不是,甚至於都不用考慮穩定排序的事情。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章