php排序 asort usort实例 对数组的多个字段排序 稳定排序

php中有很多排序函数,下面是常用的一些:
  • sort() 函数用于对数组单元从低到高进行排序。
  • rsort() 函数用于对数组单元从高到低进行排序。
  • asort() 函数用于对数组单元从低到高进行排序并保持索引关系。
  • arsort() 函数用于对数组单元从高到低进行排序并保持索引关系。
  • usort() 使用用户自定义的比较函数对数组中的值进行排序
  • uasort() 使用用户自定义的比较函数对数组中的值进行排序并保持索引关联
sort()用法很简单,就不多说了。

接下来我们看一个案例:

有如下一个数组

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

ts表示时间(戳),gold表示金币。第一次的需求是按时间排序,时间新的排前面(ts越大表示越新)并保持其他数据不错乱,即倒序排这个数组。下面先用arsort()来处理。如下函数的思路是,先将所有的ts的值保持次序不变加入到一个新的数组sa,然后倒序排这个sa并保持其索引关系,比如说排完之后ts=>9的就是sa的首个元素,但它是sa[5],其实就是按照排好后的次序得到了所有原$sorted_array的索引。依次加入新数组就能得到结果

  1. print_r(sort_via_key($sorted_array, 'ts'));
  2. function sort_via_key($data, $key)
  3. {
  4.     if(empty($data)) return array();
  5.     $ret = array();
  6.     $sorted_arr = array();
  7.     foreach ($data as $i => $_item)
  8.     {
  9.         $sorted_arr[$i] = $_item[$key];
  10.     }
  11.     arsort($sorted_arr);
  12.     foreach ($sorted_arr as $i => $_item)
  13.     {
  14.         $ret[] = $data[$i];
  15.     }
  16.     return $ret;
  17. }

结果输出如下:

  1. Array
  2. (
  3.     [0] => Array
  4.         (
  5.             [ts] => 9
  6.             [gold] => 7
  7.         )
  8.     [1] => Array
  9.         (
  10.             [ts] => 8
  11.             [gold] => 10
  12.         )
  13.     [2] => Array
  14.         (
  15.             [ts] => 5
  16.             [gold] => 7
  17.         )
  18.     [3] => Array
  19.         (
  20.             [ts] => 3
  21.             [gold] => 7
  22.         )
  23.     [4] => Array
  24.         (
  25.             [ts] => 3
  26.             [gold] => 4
  27.         )
  28.     [5] => Array
  29.         (
  30.             [ts] => 1
  31.             [gold] => 20
  32.         )
  33. )

OK,搞定。可是接下来又有了新的需求,首先按照gold来排,金币多的排前面,金币相同时才按时间来排。此时你也许会想这很简单啊,我们已经有了排序的函数,刚才用时间(ts)排了,接下来再用gold排一遍,不就好了吗。

  1. sort_via_key($sorted_array, 'gold')

好,我们来看看排完的结果:

  1. Array
  2. (
  3.     [0] => Array
  4.         (
  5.             [ts] => 1
  6.             [gold] => 20
  7.         )
  8.     [1] => Array
  9.         (
  10.             [ts] => 8
  11.             [gold] => 10
  12.         )
  13.     [2] => Array
  14.         (
  15.             [ts] => 9
  16.             [gold] => 7
  17.         )
  18.     [3] => Array
  19.         (
  20.             [ts] => 3
  21.             [gold] => 7
  22.         )
  23.     [4] => Array
  24.         (
  25.             [ts] => 5
  26.             [gold] => 7
  27.         )
  28.     [5] => Array
  29.         (
  30.             [ts] => 3
  31.             [gold] => 4
  32.         )
  33. )

gold同时为7的情况下,出问题了把。出现这个问题的原因在于arsort并不是一种稳定的排序,他把刚才排好的顺序打乱了。
接下来先说说usort。其实我们刚才写的sort_via_key函数,用usort很简单就可以实现了。usort的用法,PHP手册里有详细说明:http://www.php.net/manual/zh/function.usort.php,简单来说就是提供一个回调的比较函数,比较函数必须在第一个参数被认为小于,等于或大于第二个参数时分别返回一个小于,等于或大于零的整数。

我们只需提供如下比较函数就能完成第一个需求:

  1. usort($sorted_array, "cmp_ts_desc");
  2. function cmp_ts_desc($a, $b)
  3. {
  4.     if ($a['ts'] == $b['ts']) {
  5.         return 0;
  6.     }
  7.     return ($a['ts'] < $b['ts']) ? 1 : -1;   //倒序的话a<b返回大于0,正序a<b返回小于0
  8. }

看上去简单多了吧。
好,该是解决这个问题的时候了。我们可以提供一个这样的函数

  1. function multi_compare($a, $b)
  2. {
  3.     $criteria = array(
  4.         'gold'=>'desc',
  5.         'ts'=>'desc' //这里还可以根据需要继续加条件 如:'x'=>'asc'等
  6.     );
  7.     foreach($criteria as $what => $order){
  8.         if($a[$what] == $b[$what]){
  9.             continue;
  10.         }
  11.         return (($order == 'desc')?-1:1) * (($a[$what] < $b[$what]) ? -1 : 1);
  12.     }
  13.     return 0;
  14. }

此时只用

  1. usort($sorted_array, "multi_compare");

就OK了,结果如下:

  1. Array
  2. (
  3.     [0] => Array
  4.         (
  5.             [ts] => 1
  6.             [gold] => 20
  7.         )
  8.     [1] => Array
  9.         (
  10.             [ts] => 8
  11.             [gold] => 10
  12.         )
  13.     [2] => Array
  14.         (
  15.             [ts] => 9
  16.             [gold] => 7
  17.         )
  18.     [3] => Array
  19.         (
  20.             [ts] => 5
  21.             [gold] => 7
  22.         )
  23.     [4] => Array
  24.         (
  25.             [ts] => 3
  26.             [gold] => 7
  27.         )
  28.     [5] => Array
  29.         (
  30.             [ts] => 3
  31.             [gold] => 4
  32.         )
  33. )

这个函数正是精髓所在,即使你再多个需求多个key按照正序来排一样可以满足。仔细读这个函数,其实就是阐述了一遍需求的内容,如果不同的话就按照$criteria[0]的标准来排序,如果相同,继续$criteria[1]的标准来排序。如此轻松是不是,甚至于都不用考虑稳定排序的事情。

点赞

发表回复

电子邮件地址不会被公开。必填项已用 * 标注