php7 usort,使用usort排序的通用方法

一、问题描述

先抛出问题,有一个二维数组,有多个维度的字段,需要计算出各个维度单独的排名, 降序排列?

数据简化后如下:

// 示例数据生成

for ($i = 0; $i < 100; $i++) {

$data = [

'id' => $i,

'read_count' => mt_rand(100000, 999999),

'interactive_count' => mt_rand(10000, 99999),

'search_count' => mt_rand(1000, 9999),

'video_count' => mt_rand(100, 999),

'checkin_count' => mt_rand(100, 999),

'watch_count' => mt_rand(100, 999),

'score' => mt_rand(60, 90),

'play_status' => mt_rand(1, 2),

];

$datas[] = $data;

}

// 演示例数据

function getDemoData()

{

$datas = [

['id' => 1,'score' => 10, 'read_count' => 1000, 'search_count' => 90],

['id' => 2,'score' => 80, 'read_count' => 300, 'search_count' => 490],

['id' => 3,'score' => 10, 'read_count' => 500, 'search_count' => 590],

];

return $datas;

}

二、直接的解发

简单粗暴的办法,你必然能想到,如下:

算法:

0、定义一个排序类,每个维度定义一个排序方法

1、对每个维度分别排一次

2、分别记录每个维度的排名

/**

* 排序工具

*

* @author: salmonl

* @date: 2019-04-26

*/

class Tool

{

/**

* 各个维度排序方法

* @param $data array 数据

* @param $dimension string 维度

*

*

* @return array

*/

public static function customSort(&$data, $dimension) {

switch($dimension) {

// 实际有6个case, 这里只列出2个

case 'read':

// 第一种方式, 把比较函数放在类外面,因为usort中的比较函数是在全局查找,框架中的类是自动加载,故而可以找到

usort($data, 'read');

break;

case 'search':

// 第二种方式,把比较函数放在类中,需要传入数组[类名,方法名],

// 数组中第一个元素是类名,写Tool和self都有效, 如果customSort不用静态方法,还可以用$this;

// 这里有一个思考,比较方法search不是静态方法,为啥可以直接使用类名

// usort($data, [self, 'search']);

usort($data, ['Tool', 'search']);

break;

}

}

public function search($a, $b) {

if ($a['search_count'] == $b['search_count']) {

return 0;

}

return ($a['search_count'] < $b['search_count']) ? 1 : -1;

}

}

// 在类外,属全局函数

function read($a, $b) {

if ($a['read_count'] == $b['read_count']) {

return 0;

}

return ($a['read_count'] < $b['read_count']) ? 1 : -1;

}

$datas = getDemoData();

// read rank

Tool::customSort($datas, 'read');

print_r($datas);

Tool::customSort($datas, 'search');

print_r($datas);

$tool = new Tool();

$tool->customSort($datas, 'search');

print_r($datas);

三、通用方法

当你把6个方法都写了,你就会发现很长,你可能会想,能不能写一个通用的方法呢?

参考手册,写了如下测试脚本,满足要求

function build_sorter($key) {

return function ($a, $b) use ($key) {

if ($a[$key] == $b[$key]) {

return 0;

}

return ($a[$key] < $b[$key]) ? 1 : -1;

};

}

$datas = getDemoData();

$res = usort($datas, build_sorter('read_count'));

print_r($datas);

但是放到类中发现,无法传递参数,

提示:Warning: usort() expects parameter 2 to be a valid callback, class ‘Tool’ does not have a method ‘build_sorter(‘read’)’

class Tool

{

public static function customSort(&$data, $dimension) {

usort($data, ['Tool', "build_sorter('$dimension')"]);

}

public static function build_sorter($key) {

return function ($a, $b) use ($key) {

if ($a[$key] == $b[$key]) {

return 0;

}

return ($a[$key] < $b[$key]) ? 1 : -1;

};

}

}

$datas = getDemoData();

// read rank

Tool::customSort($datas, 'read');

print_r($datas);

通过探索,usort的比较函数直接使用匿名函数的use传递参数即可

class Tool

{

public static function customSort(&$datas, $key) {

usort($datas, function ($a, $b) use ($key) {

if ($a[$key] == $b[$key]) {

return 0;

}

return ($a[$key] < $b[$key]) ? 1 : -1;

});

}

}

$datas = getDemoData();

// read rank

Tool::customSort($datas, 'read');

print_r($datas);

另外还可以通过类属性传递,参考这里

四、总结

usort自定义排序常用用法汇总如下:

$datas = getDemoData();

// 不使用匿名函数

function score($a, $b) {

if ($a['score'] == $b['score']) {

return 0;

}

// 按照score降序,返回1表示需要交换

return ($a['score'] < $b['score']) ? 1 : -1;

}

$res = usort($datas, 'score');

print_r($datas);

// 使用匿名函数

usort($datas, function ($a, $b) {

if ($a['score'] == $b['score']) {

return 0;

}

return ($a['score'] < $b['score']) ? 1 : -1;

});

print_r($datas);

// 使用宇宙飞船表达式(PHP7+)

usort($datas, function ($a, $b) use ($order) {

// 左右相同返回0, 左 > 右 返回1, 否则返回-1。

if ('desc' == $order) {

return -($a['score'] <=> $b['score']);

} elseif ('asc' == $order) {

return ($a['score'] <=> $b['score']);

}

});

echo 3<=>3; // 0

echo 3<=>2; // 1

echo 2<=>3; // -1

print_r($datas);

// 使用类中的方法

class Tool

{

public function cmpCommon($a, $b) {

return -($a['score'] <=> $b['score']);

}

public static function cmpStatic($a, $b) {

return -($a['score'] <=> $b['score']);

}

}

// 使用类名必须调用静态方法, 调用非静态方法报错

// Warning: usort() expects parameter 2 to be a valid callback, non-static method Tool::cmpCommon() should not be called statically

usort($datas, ['Tool', 'cmpStatic']);

print_r($datas);

// 使用对象,静态方法和非静态方法都可以调用。因为静态方法通过类和对象都可以访问

$obj = new Tool();

usort($datas, [$obj, 'cmpCommon']);

usort($datas, [$obj, 'cmpStatic']);

print_r($datas);

注意:usort()中的比较函数,如果不存在或者调用不到,PHP会有Warning提示,但是数据依然会返回,只是没有排序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值