按降序排序软件版本的数组

4

如何对这个版本值数组进行排序?

$available_databases = array(
    "4.0.1",
    "trunk",
    "branch",
    "4.1.0",
    "4.0.3"
);

以便结果为

4.1.0
4.0.3
4.0.1
branch
trunk
4个回答

5
你应该使用 usort 函数来排序。
$isVersion = function($a) { return is_numeric( str_replace('.', '', $a) ); };
$sortFunction = function($a, $b) use($isVersion) { 
    if( $isVersion($a) && $isVersion($b) ) { 
        return version_compare($b, $a); // reversed for your proper ordering
    } elseif( $isVersion($a) ) { 
        return -1;
    } elseif( $isVersion($b) ) { 
        return 1;
    } else { 
        return strcasecmp($a, $b);
    }
};

usort($yourArray, $sortFunction);
usort函数允许您使用自定义比较回调函数。我已经为您编写了一个符合您要求的逻辑的回调函数:如果两个可比较的项目都是版本号,则使用version_compare函数进行比较,并反转参数以使其按降序排列。如果第二个可比较的项目是字符串,而第一个是版本号,则认为版本号“低于”字符串,反之亦然。如果两个项目都是字符串,则使用strcasecmp比较函数来确定正确的顺序。

使用示例:codepad

只是一个提醒: 如果$a和/或$b不是版本号,词法排序(如strcasecmp)已经将它们按正确顺序排序(先数字,然后是名称)。我认为您可以删掉中间的两个情况。 - cHao
看起来这只能在 PHP 5.3.0 及以上版本中运行,5.2.* 会抛出错误。 - uınbɐɥs
1
@Shaquin:而大多数服务器,你实际上在意时间和内存使用情况,在跑5.3。:)那些仍在运行5.2的在线解释器需要更新。 - cHao
当我将你的代码复制到Eclipse中时,function被标记为语法错误。我可以看到它在codepad中可以工作,但有什么办法可以让它在Eclipse中工作吗? - Radek
@Radek:如果Eclipse不能识别这是有效的PHP代码,那么它要么需要更新,要么比我记得的还糟糕。PHP 5.3已经发布超过3年了,在互联网世界里,这就像是永远。 - cHao
显示剩余4条评论

2

您可以使用PHP内置的数组操作等工具来帮助您完成大量繁重的工作,从而减少许多表面上的复杂性:

$names = preg_grep('/^\D/', $arr);
$versions = preg_grep('/^\d/', $arr);

usort($versions, 'version_compare');
usort($names, 'strcasecmp');

$sorted = array_merge(array_reverse($versions), $names);

1

可以使用一些数组函数和几个循环来完成。

示例:

<?php
$arr = array("4.0.1", "trunk", "branch", "4.1.0", "4.0.3", "1.2", "1.31", "1.10", "1.4.5");
natsort($arr);
$count = count($arr);
$alpha = array();
$new_arr = array();
for($i = 0; $i < $count; $i++) {
    if(!is_numeric(str_replace('.', '', $arr[$i]))) {
        $alpha[] = $arr[$i];
    } else {
        $new_arr[] = $arr[$i];
    }
    $arr[$i] = null;
}
rsort($new_arr);
sort($alpha);
$new_arr = array_merge($new_arr, $alpha);
var_dump($new_arr);
?>

这里有演示。


相信他想要数字部分降序排列,字母部分升序排列,否则很棒的演示。 - shaunhusain
@shaunhusain 不过它确实按照他想要的顺序对数组进行了排序,是吗? - uınbɐɥs
没有注意到他想要4.1.0在数字列表中首先出现而不是最后一个,我认为基本问题在于他希望对ASCII字符进行升序和降序排序的混合。基本上我能想到的唯一解决办法是将数组分成两个数组分别排序然后重新组合,但是对于下面提供的解决方案我不熟悉。我认为你的答案遇到了与natcasesort解决方案相同的问题。在阅读usort解决方案之后,它似乎是正确的。 - shaunhusain
1
嗯,有趣。我想知道为什么使用比较函数不会更快,除非涉及到要检查的条件数量(如果只是移动指针而不是复制值,则内存使用是可以理解的)。如果我是OP或者能再次点赞你,我会这样做。 - shaunhusain
1
@Shaquin:速度差异似乎是由于使用了print_r而不是var_dump。请参见我的ideone编辑,只更改了这个(并修复了函数名称)。 - cHao
显示剩余6条评论

0

你只需要反转 version_compare() 的评估。

代码:(演示)

$array = ["4.0.1", "trunk", "branch", "4.1.0", "4.0.3"];

usort($array, function($a, $b) {
    return version_compare($b, $a);
});

var_export($array);

输出:

array (
  0 => '4.1.0',
  1 => '4.0.3',
  2 => '4.0.1',
  3 => 'branch',
  4 => 'trunk',
)

PHP7.4开始,可以使用箭头函数语法。(演示)

usort($array, fn($a, $b) => version_compare($b, $a));

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