这个问题旨在作为PHP中关于数组排序的问题的参考。很容易认为您的特定情况是独特的,值得提出一个新问题,但大多数情况实际上是本页上某个解决方案的微小变化。 如果你的问题是这个问题的副本,请要求重新打开你的问题,只有当你能解释为什么它与下面所有的问题都有显著不同时。

我如何排序一个数组在PHP? 我如何排序一个复杂的数组在PHP? 如何在PHP中排序对象数组?


基本一维数组;包括多维数组,包括对象数组;包括根据一个数组对另一个数组排序 用SPL排序 稳定的排序

使用PHP现有函数的实际答案见1。,关于排序算法的学术详细答案(PHP函数实现,在非常非常复杂的情况下可能需要它),请参见2。


当前回答

稳定的排序

假设你有一个这样的数组:

['Kale', 'Kaleidoscope', 'Aardvark', 'Apple', 'Leicester', 'Lovely']

现在你只想对第一个字母排序:

usort($array, function($a, $b) {
    return strcmp($a[0], $b[0]);
});

结果是:

['Apple', 'Aardvark', 'Kale', 'Kaleidoscope', 'Lovely', 'Leicester']

那种东西不稳定!

敏锐的观察者可能已经注意到,数组排序算法(快速排序)并没有产生稳定的结果,并且相同首字母的单词之间的原始顺序没有被保留。这种情况很简单,我们应该比较整个字符串,但是让我们假设您的用例更复杂,比如在不同的字段上连续进行两次排序,它们不应该相互抵消。

施瓦兹变换

Schwartzian变换,也称为装饰-排序-不装饰习语,它使用固有的不稳定排序算法来实现稳定排序。

首先,你用另一个数组装饰每个数组元素,这个数组包含一个主键(value)和一个辅助键(它的索引或位置):

array_walk($array, function(&$element, $index) {
    $element = array($element, $index); // decorate
});

这将数组转换为:

[
    ['Kale', 0], ['Kaleidoscope', 1], 
    ['Aardvark', 2], ['Apple', 3], 
    ['Leicester', 4], ['Lovely', 5]
]

现在,我们调整比较步骤;我们再次比较第一个字母,但如果它们相同,则使用次键来保留原来的顺序:

usort($array, function($a, $b) {
    // $a[0] and $b[0] contain the primary sort key
    // $a[1] and $b[1] contain the secondary sort key
    $tmp = strcmp($a[0][0], $b[0][0]);

    if ($tmp != 0) {
        return $tmp; // use primary key comparison results
    }

    return $a[1] - $b[1]; // use secondary key
});

之后,我们进行装饰:

array_walk($array, function(&$element) {
    $element = $element[0];
});

最终结果:

['Aardvark', 'Apple', 'Kale', 'Kaleidoscope', 'Leicester', 'Lovely']

重用呢?

你必须重写比较函数来处理转换后的数组元素;你可能不想编辑你精致的比较函数,所以这里有一个比较函数的包装器:

function stablecmp($fn)
{
    return function($a, $b) use ($fn) {
        if (($tmp = call_user_func($fn, $a[0], $b[0])) != 0) {
            return $tmp;
        } else {
            return $a[1] - $b[1];
        }
    };
}

让我们使用这个函数来编写排序步骤:

usort($array, stablecmp(function($a, $b) {
    return strcmp($a[0], $b[0]);
}));

瞧!您的原始比较代码回来了。

其他回答

有几种方法可以对数组进行排序。我将提到一些完成这项任务的方法。首先,我将给出一个整数数组,称为'$numbers'。

$number = array(8,9,3,4,0,1,2);

这是创建数组的正常方式。假设我想要对这个数组进行升序排序。为此,可以使用'sort()'方法。

<?php

    $number = array(8,9,3,4,0,1,2);
    sort($number);

   foreach ($number as $value) {
       echo $value."  ";
   }
?>

现在考虑它的输出,

你可以看到打印的数字数组是排序的。如果你想要该数字数组排序是降序的,'rsort()'方法可以用于该任务。

<?php

     $number = array(8,9,3,4,0,1,2);
     rsort($number);

     foreach ($number as $value) {
        echo $value."  ";
     }
?>

考虑输出..

现在数组按降序排序。让我们考虑一个关联数组。我将给出一个关联数组(关联数组的意思是,每个索引都有唯一键值的数组),就像这样,

$number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);

那么,现在我想根据它们的值对这个数组进行升序排序。' sort()'方法可以用于此。

<?php

   $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
   asort($number);

   foreach ($number as $value) {
      echo $value."  ";
    }
?>

如果根据它们的值降序排序,则可以使用'arsort()'方法。 假设您想要根据键值对数组进行排序。在这种情况下,可以使用'ksort()'方法。

<?php

     $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
     ksort($number);

     foreach ($number as $value) {
         echo $value."  ";
     }
?>

现在考虑输出。

现在数组根据它们的键值排序。如果您想根据键值降序排序数组,可以使用'krsort()'方法。

<?php

    $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
    krsort($number);

    foreach ($number as $value) {
       echo $value."  ";
    }
?>

现在,关联数组按照键值降序排序。看看输出。

这些是php中按升序或降序排序数组的一些方法。我希望你能有所了解。谢谢你!

基本一维数组

$array = array(3, 5, 2, 8);

适用的排序函数:

排序 函数 带点 arsort 的作用 natcasesort ksort 作用

它们之间的区别仅仅在于是否保留键值关联(“a”函数),是从低到高排序还是反向排序(“r”),是对值排序还是对键排序(“k”),以及如何比较值(“nat”vs. normal)。有关概述和进一步细节的链接,请参阅http://php.net/manual/en/array.sorting.php。

多维数组,包括对象数组

$array = array(
    array('foo' => 'bar', 'baz' => 42),
    array('foo' => ...,   'baz' => ...),
    ...
);

如果你想根据每个条目的'foo'键对$array排序,你需要一个自定义比较函数。上面的排序和相关函数工作在简单的值上,它们知道如何比较和排序。PHP并不简单地“知道”如何处理复杂的值,例如数组('foo' => 'bar', 'baz' => 42);所以你需要讲出来。

为此,需要创建一个比较函数。该函数接受两个元素,如果认为这两个元素相等,则必须返回0,如果第一个值较低则返回一个小于0的值,如果第一个值较高则返回一个大于0的值。这就是所需要的:

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

通常,您会希望使用匿名函数作为回调。如果您想使用方法或静态方法,请参阅在PHP中指定回调的其他方法。

然后使用下列函数之一:

usort uasort uksort

同样,它们的区别只在于是否保持键-值关联并按值或键排序。详细信息请阅读他们的文档。

使用示例:

usort($array, 'cmp');

usort will take two items from the array and call your cmp function with them. So cmp() will be called with $a as array('foo' => 'bar', 'baz' => 42) and $b as another array('foo' => ..., 'baz' => ...). The function then returns to usort which of the values was larger or whether they were equal. usort repeats this process passing different values for $a and $b until the array is sorted. The cmp function will be called many times, at least as many times as there are values in $array, with different combinations of values for $a and $b every time.

要习惯这个想法,试试这个:

function cmp($a, $b) {
    echo 'cmp called with $a:', PHP_EOL;
    var_dump($a);
    echo 'and $b:', PHP_EOL;
    var_dump($b);
}

您所做的只是定义了一个自定义方法来比较两个项目,这就是您所需要的。这适用于各种价值观。

顺便说一下,这适用于任何值,这些值不一定是复杂的数组。如果你想要进行自定义比较,你也可以在简单的数字数组上进行比较。

Sort通过引用进行排序,不返回任何有用的东西!

请注意,数组排序到位,您不需要将返回值分配给任何东西。$array = sort($array)将数组替换为true,而不是一个排序的数组。只是数组($);的工作原理。

自定义数值比较

如果你想按baz键排序,它是数字,你所需要做的就是:

function cmp(array $a, array $b) {
    return $a['baz'] - $b['baz'];
}

感谢MATH的力量,这将返回一个< 0,0或> 0的值,取决于$a是否小于、等于或大于$b。

注意,这对于浮点值并不适用,因为它们将被简化为int并失去精度。使用显式的-1、0和1返回值代替。

对象

如果你有一个对象数组,它的工作方式是一样的:

function cmp($a, $b) {
    return $a->baz - $b->baz;
}

功能

你可以在比较函数中做任何你需要做的事情,包括调用函数:

function cmp(array $a, array $b) {
    return someFunction($a['baz']) - someFunction($b['baz']);
}

字符串

第一个字符串比较版本的快捷方式:

function cmp(array $a, array $b) {
    return strcmp($a['foo'], $b['foo']);
}

STRCMP和CMP完全一样,它返回-1 0或1。

宇宙飞船操作符

PHP 7引入了宇宙飞船操作符,它统一并简化了不同类型之间的相等/较小/较大比较:

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

按多个字段排序

如果你想主要根据foo排序,但如果foo对两个元素都相等,则按baz排序:

function cmp(array $a, array $b) {
    if (($cmp = strcmp($a['foo'], $b['foo'])) !== 0) {
        return $cmp;
    } else {
        return $a['baz'] - $b['baz'];
    }
}

对于那些熟悉的人来说,这相当于一个带有ORDER BY foo, baz的SQL查询。 还可以查看这个非常简洁的简写版本,以及如何为任意数量的键动态创建这样的比较函数。

按手动、静态顺序排序

如果你想将元素按“手动顺序”排序,比如“foo”,“bar”,“baz”:

function cmp(array $a, array $b) {
    static $order = array('foo', 'bar', 'baz');
    return array_search($a['foo'], $order) - array_search($b['foo'], $order);
}

对于上述所有问题,如果你使用的是PHP 5.3或更高版本(你真的应该这样做),请使用匿名函数来缩短代码,并避免出现另一个全局函数:

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

这就是对一个复杂的多维数组进行排序的简单程度。同样,就像教PHP如何分辨两个项中哪一个“更大”一样;让PHP来做实际的排序。

同样,对于上述所有参数,要在升序和降序之间切换,只需交换$a和$b参数。例如:

return $a['baz'] - $b['baz']; // ascending
return $b['baz'] - $a['baz']; // descending

根据一个数组对另一个数组排序

然后是特殊的array_multisort,它可以让你根据一个数组对另一个数组排序:

$array1 = array( 4,   6,   1);
$array2 = array('a', 'b', 'c');

这里的预期结果是:

$array2 = array('c', 'a', 'b');  // the sorted order of $array1

使用array_multisort来实现:

array_multisort($array1, $array2);

从PHP 5.5.0开始,你可以使用array_column从多维数组中提取一个列,并对该列上的数组进行排序:

array_multisort(array_column($array, 'foo'), SORT_DESC, $array);

你也可以对多个列进行排序:

array_multisort(array_column($array, 'foo'), SORT_DESC,
                array_column($array, 'bar'), SORT_ASC,
                $array);

从PHP 7.0.0开始,您还可以从对象数组中提取属性。


如果你有更多的常见情况,请随意编辑这个答案。

这个页面非常全面,但我想再补充一点关于宇宙飞船操作符(三向比较操作符)的强大实用程序——PHP7+的一个漂亮的孩子。

使用太空船操作符实现多个排序条件

这在减少代码膨胀和提高可读性方面取得了很大的进步。

当编写自定义sort(usort()/uasort()/uksort())函数来处理多个条件时,只需要在运算符的两侧编写平衡数组并返回结果。没有更多嵌套的条件块或多个返回。

操作符两边的元素将从左到右遍历,一次一个,一旦遇到不连接的元素或元素都进行了比较,就返回求值。

用于演示的示例数据:

$multidimArray = [
    'a' => [
        'boolean' => true,
        'natString' => 'text10',
        'object' => (object)['prop' => 2],
        'float' => -.5,
        'mixed' => []
    ],
    'b' => [
        'boolean' => true,
        'natString' => 'text12',
        'object' => (object)['prop' => 4],
        'float' => 0,
        'mixed' => null
    ],
    'c' => [
        'boolean' => false,
        'natString' => 'text100',
        'object' => (object)['prop' => 9],
        'float' => -.5,
        'mixed' => false
    ],
    'd' => [
        'boolean' => true,
        'natString' => 'text1',
        'object' => (object)['prop' => 9],
        'float' => -5,
        'mixed' => "\0"
    ],
    'e' => [
        'boolean' => false,
        'natString' => 'text2',
        'object' => (object)['prop' => 2],
        'float' => .5,
        'mixed' => ''
    ]
];

演示(为了避免Stackoverflow页面膨胀,请查看输出的演示链接):

Sorting logic: boolean DESC (false = 0, true = 1, so trues before falses) float ASC uasort($multidimArray, function($a, $b) { return [$b['boolean'], $a['float']] <=> [$a['boolean'], $b['float']]; }); Sorting logic: mixed ASC object ASC boolean ASC uasort($multidimArray, function($a, $b) { return [$a['mixed'], $a['object']->prop, $a['boolean']] <=> [$b['mixed'], $b['object']->prop, $b['boolean']]; }); Sorting logic: property count of object ASC iterability of mixed DESC natString length ASC natString ASC uasort($multidimArray, function($a, $b) { return [count(get_object_vars($a['object'])), is_iterable($a['mixed']), strlen($a['natString']), $a['natString']] <=> [count(get_object_vars($b['object'])), is_iterable($b['mixed']), strlen($b['natString']), $b['natString']]; });

这种语法允许您以优雅的方式对值、函数结果、深层嵌套数据和排序方向进行排序。这绝对值得放在你的php工具带中……用于处理非数据库数据的情况——因为SQL当然是一种更明智的技术。

在PHP7.4中,您可以自行决定对这些匿名函数使用箭头语法。与箭头语法相同的脚本。

最简单的方法是使用usort函数对数组进行排序,而不需要任何循环: 下面是一个例子:

   $array_compare= array("0" =>4,"1"=>2,"2"=>500,"3"=>100);

这将按降序排序:

usort($array_compare, function($a, $b) {
        return ($b['x1'] - $a['x1']) > 0 ? 1 :-1;
    });

这将按发送顺序排序:

usort($array_compare, function($a, $b) {
        return ($b['x1'] - $a['x1']) < 0 ? 1 :-1;
    });

如果你想按键值排序,那么你可以做一行,优雅而清晰。这将按价格递增来排序。使用array_multisort和array_column。

   Array([0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => coffee [price] => 9.99 ) [2] => Array ( [name] => rice [price] => 4.04 ) )

   array_multisort (array_column($array, 'price'), SORT_ASC, $array);

生产

     Array ( [0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => rice [price] => 4.04 ) [2] => Array ( [name] => coffee [price] => 9.99 ) )