按子数组值对PHP数组进行排序

142

我有以下数组结构:

Array
        (
            [0] => Array
                (
                    [configuration_id] => 10
                    [id] => 1
                    [optionNumber] => 3
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [1] => Array
                (
                    [configuration_id] => 9
                    [id] => 1
                    [optionNumber] => 2
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [2] => Array
                (
                    [configuration_id] => 8
                    [id] => 1
                    [optionNumber] => 1
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )
    )

如何基于 optionNumber 按递增方式对数组进行排序?

结果应该如下所示:

Array
        (
            [0] => Array
                (
                    [configuration_id] => 8
                    [id] => 1
                    [optionNumber] => 1
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [1] => Array
                (
                    [configuration_id] => 9
                    [id] => 1
                    [optionNumber] => 2
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [2] => Array
                (
                    [configuration_id] => 10
                    [id] => 1
                    [optionNumber] => 3
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )
    )
8个回答

250
使用usort
function cmp_by_optionNumber($a, $b) {
  return $a["optionNumber"] - $b["optionNumber"];
}

...

usort($array, "cmp_by_optionNumber");

在PHP ≥5.3中,你应该使用一个匿名函数来替代:
usort($array, function ($a, $b) {
    return $a['optionNumber'] - $b['optionNumber'];
});

请注意,上述代码都假设$a['optionNumber']是一个整数。如果它们是字符串,请使用@St. John Johnson's solution
在PHP ≥7.0中,使用太空船运算符<=>代替减法,以避免溢出/截断问题。
usort($array, function ($a, $b) {
    return $a['optionNumber'] <=> $b['optionNumber'];
});

2
这并没有真正帮助我,因为usort要求我提供一个函数来使用——这是我无法理解的困难部分。 - Sjwdavies
20
他刚刚给了你要使用的函数。你必须接受并理解,有时候没有内置的函数能够满足你的需求,这时候你需要自己编写代码。比较函数只需要返回1、0或-1来表示两个元素的排序顺序即可。 - Tesserex
1
我进一步研究了usort,发现它实际上非常酷。我编写了一个简单的比较函数,但是错过了“==”符号。感谢大家的帮助。 - Sjwdavies
3
最终闭合代码:-- 使用usort函数($array, function($a,$b){ return $b["optionNumber"] - $a["optionNumber"]; }); 将数组按照"optionNumber"值从高到低排序。 - Joeri
1
我认为最好的解决方案,唯一的区别是我使用 uasort() 而不是 usort() 来保留键值 :) - rAthus
显示剩余8条评论

67

使用usort函数

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

9
@BenSinclair,那是因为Kenny的解决方案是针对数字的,而这个解决方案是针对字符串的。它们都是正确的 :-) 对于这种替代方案,点个赞+1。 - kubilay
使用strcasecmp而不是strcmp进行不区分大小写的排序。 - user570605
我们能否在数组中定义第二个键,这意味着我们首先使用optionNumber进行排序,然后再使用lastUpdated进行排序。我们该如何做到这一点? - Bhavin Thummar

19

我同时使用了 KennyTMAJ Quick 提供的两种解决方案,并编写了一个函数,可以帮助解决许多实例,例如使用ASC或DESC排序保留键,或者如果您的数组中有对象作为子元素

以下是此函数(适用于PHP7及更高版本,因为其包含太空船操作符):

/**
 * @param array $array
 * @param string $value
 * @param bool $asc - ASC (true) or DESC (false) sorting
 * @param bool $preserveKeys
 * @return array
 * */
function sortBySubValue($array, $value, $asc = true, $preserveKeys = false)
{
    if ($preserveKeys) {
        $c = [];
        if (is_object(reset($array))) {
            foreach ($array as $k => $v) {
                $b[$k] = strtolower($v->$value);
            }
        } else {
            foreach ($array as $k => $v) {
                $b[$k] = strtolower($v[$value]);
            }
        }
        $asc ? asort($b) : arsort($b);
        foreach ($b as $k => $v) {
            $c[$k] = $array[$k];
        }
        $array = $c;
    } else {
        if (is_object(reset($array))) {
            usort($array, function ($a, $b) use ($value, $asc) {
                return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
            });
        } else {
            usort($array, function ($a, $b) use ($value, $asc) {
                return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
            });
        }
    }

    return $array;
}

用法:

sortBySubValue($array, 'optionNumber', true, false);

编辑

第一部分可以使用uasort()进行重写,而且函数会更短(由于宇宙飞船操作符的存在,该方法仅适用于PHP7及以上版本):

/**
 * @param array $array
 * @param string $value
 * @param bool $asc - ASC (true) or DESC (false) sorting
 * @param bool $preserveKeys
 * @return array
 * */
function sortBySubValue($array, $value, $asc = true, $preserveKeys = false)
{
    if (is_object(reset($array))) {
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) {
            return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
        }) : usort($array, function ($a, $b) use ($value, $asc) {
            return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
        });
    } else {
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) {
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        }) : usort($array, function ($a, $b) use ($value, $asc) {
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        });
    }
    return $array;
}

1
为了让这对我起作用,我必须在比较 $a$b 值时使用 >(大于)而不是 -(减号),因为我正在比较字符串。尽管如此,它仍然有效。 - James
1
@James 你说得对。我修改了答案并添加了太空船运算符(<=>)。现在应该可以正常工作了。 - Pigalev Pavel
有没有办法使这个不区分大小写? - loeffel

18

使用array_multisort(), array_map()

array_multisort(array_map(function($element) {
      return $element['optionNumber'];
  }, $array), SORT_ASC, $array);

print_r($array);

演示


3
这很容易操作。谢谢。我所需要做的就是更改我的列名,然后它就起作用了。 - Kobus Myburgh
4
这也会保留父数组的键。 - JonnyS
我知道这个问题现在有点老了,但我有一个问题:我看到它确实起作用,但它是如何工作的?我已经阅读了php.net上的array_multisort文档,但这仍然对我来说不太清楚。 - Renan Lazarotto
1
这是最好的答案,它不会影响ob_start的输出。谢谢。 - dwi kristianto

4

两种最现代、最简洁的方法是:

  1. usort() with arrow function syntax and a spaceship (3-way comparison) operator. (Demo)

    usort($array, fn($a, $b) =>
        $a['optionNumber'] <=> $b['optionNumber']
    );
    

    $a <=> $b gives ascending sorting; $b <=> $a gives descending sorting.

  2. array_multisort() with an array_column() call to isolate the value to compare. (Demo)

    array_multisort(
        array_column($array, 'optionNumber'),
        $array
    );
    

    It is not necessary to include the sorting direction flag because ascending is the default/implied direction when omitted.

以上两种方法都要求目标数组列存在于所有行中,否则方法将失败/中断/出错。


4
使用上述函数时,键将被删除。如果键很重要,则可以使用以下函数来保留它...但是foreach循环效率相当低下。
function subval_sort($a,$subkey) {
    foreach($a as $k=>$v) {
        $b[$k] = strtolower($v[$subkey]);
    }
    asort($b);
    foreach($b as $key=>$val) {
        $c[$key] = $a[$key];
    }
    return $c;
}
$array = subval_sort($array,'optionNumber');

如果你想要从高到低排列,请使用arsort而不是asort。

代码来源:http://www.firsttube.com/read/sorting-a-multi-dimensional-array-with-php/


3

PHP 5.3+

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

0
使用array_multisortarray_column的一行解决方案。
//your array
$yourarray = Array
          (
           "0" => Array
                  (
                    "configuration_id" => 10,
                    "id" => 1,
                    "optionNumber" => 3,
                    "optionActive" => 1,
                    "lastUpdated" => "2010-03-17 15:44:12"
                  ),
           "1" => Array
                  (
                    "configuration_id" => 9,
                    "id" => 1,
                    "optionNumber" => 2,
                    "optionActive" => 1,
                    "lastUpdated" => "2010-03-17 15:44:12"
                  ),
           "2" => Array
                  (
                    "configuration_id" => 8,
                    "id" => 1,
                    "optionNumber" => 1,
                    "optionActive" => 1,
                    "lastUpdated" => "2010-03-17 15:44:12"
                  )
);

//access optionNumber in the child arrays using array_column
array_multisort(array_column($yourarray, 'optionNumber'), SORT_ASC, $yourarray);

//print out preformatted
echo "<pre>"; print_r($images); echo "</pre>";

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