PHP中用于整数比较的strcmp等效函数(intcmp)

73

我们在 PHP 中有这个函数

strcmp(string $1,string $2) // returns -1,0, or 1;

我们没有intcmp()函数,因此我创建了一个:

function intcmp($a,$b) {
    if((int)$a == (int)$b)return 0;
    if((int)$a  > (int)$b)return 1;
    if((int)$a  < (int)$b)return -1;
}

这感觉不太好,你们觉得呢?

这是一部分用于按照传入的排序值对Javascript进行排序的类。

class JS
{
    // array('order'=>0,'path'=>'/js/somefile.js','attr'=>array());
    public $javascripts = array(); 
    ...
    public function __toString()
    {
        uasort($this->javascripts,array($this,'sortScripts'));
        return $this->render();
    }
    private function sortScripts($a,$b)
    {
        if((int)$a['order'] == (int)$b['order']) return 0;
        if((int)$a['order'] > (int)$b['order']) return 1;
        if((int)$a['order'] < (int)$b['order']) return -1;
    }
    ....
}

1
version_compare() 不就可以了吗? - Alix Axel
好奇的人:我有一个使用案例,需要它是1/0/-1。我有一个可以有3个标准的函数来排序数组。我将第一个标准的权重比第二个更高,所以对于字符串,我可以使用strcasecmp($a1, $b1) * $factor,但对于整数,我将不得不使用带有冗长if语句的函数。 - Redzarf
这与软件版本字符串比较有关,例如版本1.3.10比1.3.9更新。最好通过版本字符串的部分进行整数比较来执行此操作。 - Hummeling Engineering BV
2
在php 7中添加了<=> "spaceship"运算符。例如:return $a <=> $b。或者为了确保比较为整数:return (int)$a <=> (int)$b - ToolmakerSteve
太空船运算符在比较两个数字字符串时会将它们视为数字。这是太空船运算符美妙而神奇的内置功能。无需显式地将每个值转换为“int”或“float”。 - mickmackusa
7个回答

122

使用以下方式对您的数据进行排序:

function sortScripts($a, $b)
{
    return $a['order'] - $b['order'];
}

如果您想要相反的顺序,请使用 $b-$a。

如果所涉及的数字超出PHP整数范围,则 return ($a < $b) ? -1 : (($a > $b) ? 1 : 0) 更加健壮。


1
我不得不使用($b-$a)*-1来实现倒序,但是话说回来,谢谢! - Chase Wilson
5
这个实现与许多其他语言一样是有问题的 - aioobe
13
为了澄清@aioobe所说的,如果整数超过php整数范围(64位有符号),并且被隐式转换为浮点值,则此实现将发生错误。因此,虽然“($a-$b)”显然更快,但不如“($a < $b) ? -1 : (($a> $b)?1:0)”稳健,后者在所有情况下都有效。 - etherice
min(max($a - $b, -1), 1) 对于整数运算很有效,但如果你需要处理浮点数,并且希望将范围 >-1... < 0 > .. < 1 映射到 -1 或 1,上述嵌套三元运算符可能仍然更好。 - Jon Marnock
这个也会在(小)小数上出问题。所以最好使用更健壮的版本。 - Jānis Elmeris
随着太空船运算符的发明,减法和三元解决方法不再必要。[https://3v4l.org/Qogas] - mickmackusa

14

仅作为一些额外信息,有一个已经被接受的RFC进行了此操作(https://wiki.php.net/rfc/combined-comparison-operator)。

因此,比较函数将类似于...

<?php
$data = [...];
usort($data, function($left, $right){ return $left <=> $right; });
?>

这里的一个非常好的特性是,比较方式与所有其他比较完全相同。因此类型转换会按预期发生。

到目前为止,还没有像魔法般的__forCompare()方法来允许对象公开比较值。当前的提案(另一个RFC)是在比较过程中将每个对象注入到每个其他对象中,以执行比较——这似乎有点奇怪——有可能引发递归和堆栈溢出…!我认为,要么是注入用于比较的对象类型(允许对象根据比较类型表示适当的值),要么是盲目请求对象可以提供比较值的解决方案,将是更安全的解决方案。

尚未集成到PHP-NG(当前为PHP 7),但希望不久之后能够实现。


13

1
当仅第一个或第二个参数为字符串时,这同样适用于所有情况。 - Katrina
抱歉,但这是个玩笑吗?你有两个数字,然后通过将它们转换为字符串进行比较,接着函数将它们转换回整数并进行比较,就像你一开始本来要做的那样。 - Gábor
非常有用的是可以按照正确(自然)的顺序来排序字符串,例如"user.1","user.2","user.10"等等。我在PHP的usort函数中使用了它。 - Avatar

10

你可以使用

function intcmp($a,$b)
    {
    return ($a-$b) ? ($a-$b)/abs($a-$b) : 0;
    }

虽然我不看重使用这个函数的意义


这个运行得非常好!你认为它在类的上下文中能够工作吗?或者有更好的实现方式吗?我还没有找到一个好的多维数组排序标准!! - Chase Wilson
4
这个短语很巧妙,但并不是一行代码总比三行代码更简单。如果我看到这段代码,然后5分钟后才意识到它只是使用除法和模数运算返回+1/0/-1的话,我会感到困惑。说实话,我还是喜欢原始版本的代码。 - serg
1
如果你遇到减法和除法就会感到困惑吗?真的吗? - nico
令人尴尬。为了实现一个琐碎而常见的函数,需要一个绝对值、一个除法和两个减法?请像其他人一样做明显的事情。你未来的代码读者会感谢你的。 - ToolmakerSteve
@ChaseWilson 使用usort()函数和太空船操作符对多维数组进行排序非常简单/优雅。参考链接:https://dev59.com/MnA75IYBdhLWcg3wi5wr#54647220。 - mickmackusa

5

必须是+1和-1吗?如果不是,只需返回(int) $a - (int) $b。我不喜欢其他人建议的除法,也没有必要检查所有三种情况。如果它既不大于又不等于,则必定小于。

return (int) $a > (int) $b ? 1 : (int) $a == (int) $b ? 0 : -1;

1
在我看来,把三元操作符叠加使用是一种不好的做法。在这种情况下,我们会遇到运算顺序问题。修正方法如下:返回 (int) $a > (int) $b ? 1 : ( (int) $a == (int) $b ? 0 : -1 ); - msun
PHP和C的运算符顺序是否不同?除了添加括号,解释器还有其他方法来解析这个语句吗? - tomlogic
1
是的,在PHP中,三元运算符的结合性是错误的:http://phpsadness.com/sad/30 - MazeChaZer

1
乍一看,是的,感觉很不干净。除非你写这个函数时有一个好的理由,而不仅仅是使用实际的“==”,“>”和“<”运算符。创建此函数的动机是什么?
如果是我,我可能会做类似这样的事情:
$x = $a==$b ? 0 : ($a>$b ? 1 : ($a<$b ? -1 : null));

我意识到这样做同样很丑陋,而且 : null; - 不确定 PHP 是否需要它,或者我是否可以只使用 :;,但我不喜欢它,那段代码也不应该执行... 如果我知道原始需求,我会少得多的困惑!


@Andy E的意思是:我猜测的动机可能是创建一个与strcmp类似的函数,但我需要了解导致这个想法的情况。 - FrustratedWithFormsDesigner
2
这个想法是帮助排序一个JavaScript多维数组的数组。 - Chase Wilson
幸运的是,太空船(三路比较)运算符被发明了,这个答案没有任何吸引力。 - mickmackusa

1
对于字符串。
 usort($points, function ($a, $b) use ($orderFlag, $key1, $key2) {
        return strcmp($a[$key1][$key2], $b[$key1][$key2]) * $orderFlag;
    });

orderFlag => 1(升序):-1(降序)

对于数字

usort($points, function ($a, $b) use ($orderFlag, $key1, $key2) {
    return ($a[$key1][$key2] - $b[$key1][$key2]) * $orderFlag;
});

orderFlag => 1 (升序): -1 (降序)


我永远不会使用这两个片段。使用太空船运算符可以替代它们 - 没有必要使用单独的技术。 - mickmackusa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接