You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

usort排序含float值的数组时出现不符合预期的结果

问题根源:usort回调的返回值要求是整数,浮点数精度坑了你

这个问题其实是浮点数精度限制usort的回调函数规则共同导致的:

usort的回调函数明确要求返回整数

  • 返回负数:$a排在$b前面
  • 返回正数:$b排在$a前面
  • 返回0:两者相对顺序保持不变

而你直接用$a['custom_price'] - $b['custom_price']得到的是浮点数,PHP会自动把这个浮点数转为整数。当两个浮点数的差值非常接近1但略小于1时(比如0.9999999999999964),转成整数就会变成0,usort就会认为这两个元素相等,不会调整它们的顺序。

你的测试案例里发生了什么?

你直观认为16.83 - 15.83 = 1,但实际上由于浮点数的二进制存储精度问题,这个计算结果可能是一个略小于1的浮点数,转成整数后就是0。usort看到返回0,就保留了这两个元素原来的相对顺序(1176在1199前面),最终导致排序结果异常。

而当你把15.83改成14.83时,16.83 - 14.83 = 2,这个结果是精确的浮点数,转成整数是2,usort会正确把14.83的元素排在前面。

解决方法

有几种靠谱的修复方式:

1. 使用PHP 7+的太空船运算符(推荐)

太空船运算符会自动处理浮点数比较,返回符合要求的整数结果:

usort($array, function($a, $b) {
    return $a['custom_price'] <=> $b['custom_price'];
});

2. 手动判断返回-1/0/1

完全避免浮点数减法的精度问题,逻辑更清晰:

usort($array, function($a, $b) {
    if ($a['custom_price'] < $b['custom_price']) {
        return -1;
    } elseif ($a['custom_price'] > $b['custom_price']) {
        return 1;
    } else {
        return 0;
    }
});

3. 对差值取整(注意适用场景)

如果确定你的价格差值不会小于0.5,可以用round把结果转成整数:

usort($array, function($a, $b) {
    return round($a['custom_price'] - $b['custom_price']);
});

用上面任意一种方法,你的测试数组都会按照15.83 → 16.83 → 33.15的正确顺序排序。

内容的提问来源于stack exchange,提问作者Bilal Ahmed

火山引擎 最新活动